diff --git a/.codeclimate.yml b/.codeclimate.yml
index 4343c26245..f46194a7d8 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -34,11 +34,12 @@ plugins:
duplication:
enabled: true
config:
- count_threshold: 3
+ count_threshold: 4
exclude_patterns:
- - "**/test/*"
- - "**/adapter-tests/*"
- - "**/dist/*"
- - "**/*.dist.js"
+ - "**/test/*"
+ - "**/adapter-tests/*"
+ - "**/dist/*"
+ - "**/*.dist.js"
- "**/templates/*"
- - "**/_**"
\ No newline at end of file
+ - "**/_**"
+ - "**/adapter-commons/src/sort.ts"
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000000..c5848d653b
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+main/
+deno/
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
index 127eaca585..4e79b48f8e 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,16 +1,3 @@
-/*
-👋 Hi! This file was autogenerated by tslint-to-eslint-config.
-https://github.com/typescript-eslint/tslint-to-eslint-config
-
-It represents the closest reasonable ESLint configuration to this
-project's original TSLint configuration.
-
-We recommend eventually switching this configuration to extend from
-the recommended rulesets in typescript-eslint.
-https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md
-
-Happy linting! 💖
-*/
module.exports = {
"env": {
"browser": true,
@@ -19,8 +6,7 @@ module.exports = {
"node": true
},
"extends": [
- "plugin:@typescript-eslint/recommended",
- "plugin:@typescript-eslint/recommended-requiring-type-checking"
+ "plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
@@ -28,135 +14,21 @@ module.exports = {
"sourceType": "module"
},
"plugins": [
- "eslint-plugin-import",
- "eslint-plugin-prefer-arrow",
- "@typescript-eslint"
+ "@typescript-eslint",
+ "prettier"
],
+ "ignorePatterns": ["**/lib/", "**/dist/"],
"rules": {
- "prefer-rest-params": "off",
- "prefer-spread": "off",
- "@typescript-eslint/no-unsafe-member-access": "off",
- "@typescript-eslint/no-unsafe-assignment": "off",
- "@typescript-eslint/no-unsafe-argument": "off",
- "@typescript-eslint/no-unsafe-member-access": "off",
- "@typescript-eslint/no-unsafe-call": "off",
- "@typescript-eslint/no-unsafe-return": "off",
- "@typescript-eslint/no-floating-promises": "off",
- "@typescript-eslint/restrict-template-expressions": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/require-await": "off",
- "@typescript-eslint/ban-ts-comment": "off",
- "@typescript-eslint/unbound-method": "off",
- "@typescript-eslint/no-this-alias": "off",
- "@typescript-eslint/prefer-regexp-exec": "off",
- "@typescript-eslint/no-misused-promises": "off",
- "@typescript-eslint/restrict-plus-operands": "off",
- // ----
- "@typescript-eslint/adjacent-overload-signatures": "error",
- "@typescript-eslint/array-type": [
- "error",
- {
- "default": "array"
- }
- ],
- "@typescript-eslint/ban-types": "off",
- "@typescript-eslint/consistent-type-assertions": "error",
- "@typescript-eslint/dot-notation": "error",
- "@typescript-eslint/explicit-member-accessibility": [
- "error",
- {
- "accessibility": "no-public"
- }
- ],
- "@typescript-eslint/naming-convention": "off",
- "@typescript-eslint/no-empty-function": "off",
- "@typescript-eslint/no-empty-interface": "error",
+ "prettier/prettier": "error",
"@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-misused-new": "error",
- "@typescript-eslint/no-namespace": "error",
- "@typescript-eslint/no-parameter-properties": "off",
- "@typescript-eslint/no-unused-expressions": "error",
- "@typescript-eslint/no-use-before-define": "off",
- "@typescript-eslint/no-var-requires": "error",
- "@typescript-eslint/prefer-for-of": "error",
- "@typescript-eslint/prefer-function-type": "error",
- "@typescript-eslint/prefer-namespace-keyword": "error",
- "@typescript-eslint/quotes": [
- "error",
- "single"
- ],
- "@typescript-eslint/triple-slash-reference": [
- "error",
- {
- "path": "always",
- "types": "prefer-import",
- "lib": "always"
- }
- ],
- "@typescript-eslint/unified-signatures": "error",
- "arrow-parens": [
- "off",
- "always"
- ],
- "comma-dangle": "error",
- "complexity": "off",
- "constructor-super": "error",
- "eqeqeq": [
- "error",
- "smart"
- ],
- "guard-for-in": "error",
- "id-blacklist": "off",
- "id-match": "off",
- "import/order": "off",
- // "jsdoc/check-alignment": "error",
- // "jsdoc/check-indentation": "error",
- // "jsdoc/newline-after-description": "error",
- "max-classes-per-file": "off",
- "max-len": "off",
- "new-parens": "error",
- "no-bitwise": "error",
- "no-caller": "error",
- "no-cond-assign": "error",
- "no-console": "error",
- "no-debugger": "error",
- "no-empty": "off",
- "no-eval": "error",
- "no-fallthrough": "off",
- "no-invalid-this": "off",
- "no-new-wrappers": "error",
- "no-shadow": [
- "off",
- {
- "hoist": "all"
- }
- ],
- "no-throw-literal": "error",
- "no-trailing-spaces": "error",
- "no-undef-init": "error",
- "no-underscore-dangle": "off",
- "no-unsafe-finally": "error",
- "no-unused-labels": "error",
- "no-var": "error",
- "object-shorthand": "error",
- "one-var": [
- "error",
- "never"
- ],
- "prefer-arrow/prefer-arrow-functions": "off",
- "prefer-const": "error",
- "radix": "error",
- "space-before-function-paren": "error",
- "spaced-comment": [
- "error",
- "always",
- {
- "markers": [
- "/"
- ]
+ "@typescript-eslint/no-unused-vars": [
+ "warn", // or "error"
+ {
+ "argsIgnorePattern": "^_",
+ "varsIgnorePattern": "^_",
+ "caughtErrorsIgnorePattern": "^_",
+ "ignoreRestSiblings": true
}
- ],
- "use-isnan": "error",
- "valid-typeof": "off"
+ ]
}
};
diff --git a/.github/contributing.md b/.github/contributing.md
index 98df2ff804..57c8c8a011 100644
--- a/.github/contributing.md
+++ b/.github/contributing.md
@@ -8,7 +8,7 @@ Feathers embraces modularity and is broken up across multiple modules. You can f
Before creating an issue please make sure you have checked out the docs, specifically the [FAQ](https://docs.feathersjs.com/help/faq.html) section. You might want to also try searching Github. It's pretty likely someone has already asked a similar question.
-If you haven't found your answer please feel free to join our [slack channel](http://slack.feathersjs.com), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Slack and Github.
+If 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 Slack and Github.
Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues). Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**.
@@ -16,7 +16,7 @@ Issues can be reported in the [issue tracker](https://github.com/feathersjs/feat
We take security very seriously at Feathers. We welcome any peer review of our 100% open source code to ensure nobody's Feathers app is ever compromised or hacked. As a web application developer you are responsible for any security breaches. We do our very best to make sure Feathers is as secure as possible by default.
-In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Slack](http://slack.feathersjs.com) or email us at hello@feathersjs.com with details and we will respond ASAP.
+In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Discord](https://discord.gg/qa8kez8QBx) or email us at hello@feathersjs.com with details and we will respond ASAP.
For full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html).
@@ -48,7 +48,7 @@ If you've written something awesome about Feathers, for the Feathers ecosystem,
If you are looking to create a new plugin you also might want to check out the [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) that can be used to scaffold plugins to be Feathers compliant from the start.
-If you think your module would be a good core `feathersjs` module or `featherjs-ecosystem` module then please contact one of the Feathers maintainers in [Slack](http://slack.feathersjs.com) and we can discuss whether it belongs and how to get it there. :beers:
+If you think your module would be a good core `feathersjs` module or `featherjs-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:
## Contributor Code of Conduct
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index 1b770b7089..05d30a1eda 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -4,27 +4,44 @@ on: [push, pull_request]
jobs:
build:
-
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [12.x, 14.x]
+ node-version: [14.x, 18.x]
+
+ services:
+ postgres:
+ image: postgres:latest
+ env:
+ POSTGRES_DB: feathers
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_PORT: 5432
+ POSTGRES_USER: postgres
+ ports:
+ - 5432:5432
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
steps:
- - uses: actions/checkout@v2
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
- - run: npm install -g codeclimate-test-reporter
- - run: npm install
- - run: npm test
- env:
- CI: true
- - run: |
- if [ "$CODECLIMATE_REPO_TOKEN" != "" ]; then
- codeclimate-test-reporter < coverage/lcov.info
- fi
- env:
- CODECLIMATE_REPO_TOKEN: ${{ secrets.codeclimate }}
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm i npm -g
+ - run: npm install -g codeclimate-test-reporter
+ - run: npm install
+ - run: npm test
+ env:
+ CI: true
+ TEST_DB: postgres
+ - run: |
+ if [ "$CODECLIMATE_REPO_TOKEN" != "" ]; then
+ codeclimate-test-reporter < coverage/lcov.info
+ fi
+ env:
+ CODECLIMATE_REPO_TOKEN: ${{ secrets.codeclimate }}
diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml
index fe24ee5a72..12adf89b11 100644
--- a/.github/workflows/update-dependencies.yml
+++ b/.github/workflows/update-dependencies.yml
@@ -1,6 +1,6 @@
name: Update dependencies
-on:
+on:
schedule:
- cron: '0 0 1 * *'
workflow_dispatch:
@@ -8,24 +8,23 @@ jobs:
update-dependencies:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Use Node.js
- uses: actions/setup-node@v1
- with:
- node-version: '15.x'
- - run: npm ci
- - run: |
- git config user.name "GitHub Actions Bot"
- git config user.email "hello@feathersjs.com"
- git checkout -b update-dependencies-$GITHUB_RUN_ID
- - run: |
- npm run update-dependencies
- npm install
- - run: |
- git commit -am "chore(dependencies): Update dependencies"
- git push origin update-dependencies-$GITHUB_RUN_ID
- - run: |
- gh pr create --title "chore(dependencies): Update all dependencies" --body ""
- env:
- GITHUB_TOKEN: ${{secrets.CI_ACCESS_TOKEN}}
-
\ No newline at end of file
+ - uses: actions/checkout@v2
+ - name: Use Node.js
+ uses: actions/setup-node@v1
+ with:
+ node-version: '18.x'
+ - run: npm ci
+ - run: |
+ git config user.name "GitHub Actions Bot"
+ git config user.email "hello@feathersjs.com"
+ git checkout -b update-dependencies-$GITHUB_RUN_ID
+ - run: |
+ npm run update-dependencies
+ npm install
+ - run: |
+ git commit -am "chore(dependencies): Update dependencies"
+ git push origin update-dependencies-$GITHUB_RUN_ID
+ - run: |
+ gh pr create --title "chore(dependencies): Update all dependencies" --body ""
+ env:
+ GITHUB_TOKEN: ${{secrets.CI_ACCESS_TOKEN}}
diff --git a/.gitignore b/.gitignore
index 04761aa03e..691dd762f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,5 @@ dist/
# TypeScript compiled files
packages/**/lib
+packages/cli/test/build/*.tgz
+*.sqlite
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000000..6907cbaf10
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "tabWidth": 2,
+ "useTabs": false,
+ "printWidth": 110,
+ "semi": false,
+ "trailingComma": "none",
+ "singleQuote": true
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1535e139ea..9eef5abd66 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,9 @@
{
"deno.enable": true,
"deno.lint": true,
- "deno.unstable": true
+ "deno.unstable": true,
+ "deno.enablePaths": [
+ "./main",
+ "./deno"
+ ]
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abea3b3d44..32348eb03e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,949 +3,850 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)
-
+# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)
### Bug Fixes
-* **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))
-* **schema:** Do not error for schemas without properties ([#2519](https://github.com/feathersjs/feathers/issues/2519)) ([96fdb47](https://github.com/feathersjs/feathers/commit/96fdb47d45fd88a8039aa9cc9ec8aebd98672b95))
-* **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))
-
+- **errors:** Allows to pass no error message ([#2794](https://github.com/feathersjs/feathers/issues/2794)) ([f3ddab6](https://github.com/feathersjs/feathers/commit/f3ddab637e269e67e852ffce07b060bab2b085c0))
+- **koa:** Only set error code for Feathers errors ([#2793](https://github.com/feathersjs/feathers/issues/2793)) ([d3ee41e](https://github.com/feathersjs/feathers/commit/d3ee41e27b0ea5d29b344d6584ab03e48d16e2b4))
### Features
-* **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))
-* **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))
-* **schema:** Improve schema typing, validation and extensibility ([#2521](https://github.com/feathersjs/feathers/issues/2521)) ([8c1b350](https://github.com/feathersjs/feathers/commit/8c1b35052792e82d13be03c06583534284fbae82))
-
-# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)
+- **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))
+- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))
+# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)
### Bug Fixes
-* **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))
-* **adapter-commons:** Fix sorting for embedded objects ([#2488](https://github.com/feathersjs/feathers/issues/2488)) ([9c22f70](https://github.com/feathersjs/feathers/commit/9c22f70a838cb6341775d91705a7527c8fc5590e))
-* missing express types for Request, Response ([#2498](https://github.com/feathersjs/feathers/issues/2498)) ([ee67131](https://github.com/feathersjs/feathers/commit/ee67131bbaa24c54d3d781bdf8820015759ac488))
-* **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))
-
+- **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))
+- **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))
### Features
-* **authentication-oauth:** Allow dynamic oAuth redirect ([#2469](https://github.com/feathersjs/feathers/issues/2469)) ([b7143d4](https://github.com/feathersjs/feathers/commit/b7143d4c0fbe961e714f79512be04449b9bbd7d9))
-* **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))
-* **core:** Improve legacy hooks integration ([08c8b40](https://github.com/feathersjs/feathers/commit/08c8b40999bf3889c61a4d4fad97a2c4f78bafc9))
-* **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))
+- **cli:** Add ability to `npm init feathers` ([#2755](https://github.com/feathersjs/feathers/issues/2755)) ([d734931](https://github.com/feathersjs/feathers/commit/d734931ffd4f983a05d9e771ce0e43b696c2bc0e))
+- **cli:** Improve CLI interface ([#2753](https://github.com/feathersjs/feathers/issues/2753)) ([c7e1b7e](https://github.com/feathersjs/feathers/commit/c7e1b7e80aacb84441908c3d73512d9cf7557f7e))
+- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))
+- **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))
+# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)
+### Bug Fixes
+- **authentication-oauth:** Fix oAuth origin and error handling ([#2752](https://github.com/feathersjs/feathers/issues/2752)) ([f7e1c33](https://github.com/feathersjs/feathers/commit/f7e1c33de1b7af0672a302d2ba6e15d997f0aa83))
+- **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))
+- **socketio:** Reinitialize hooks on overriden setup method ([#2722](https://github.com/feathersjs/feathers/issues/2722)) ([5e8e7c4](https://github.com/feathersjs/feathers/commit/5e8e7c442238fdc929a0a36b8b8ca2b230ce761f))
+### Features
-# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)
+- 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))
+- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))
+- **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))
+- **cli:** Adding ClientService to CLI ([#2750](https://github.com/feathersjs/feathers/issues/2750)) ([1d45427](https://github.com/feathersjs/feathers/commit/1d45427988521ac028755cbe128685fcdf34f636))
-**Note:** Version bump only for package feathers
+# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)
+### Bug Fixes
+- **authentication-client:** Properly handle missing token error ([#2700](https://github.com/feathersjs/feathers/issues/2700)) ([160746e](https://github.com/feathersjs/feathers/commit/160746e2bceb465fd1b6a003415f8ab38daba521))
+- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))
+- **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))
+- **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))
+- **mongodb:** Ensure transactions are used properly in create ([#2699](https://github.com/feathersjs/feathers/issues/2699)) ([fe22615](https://github.com/feathersjs/feathers/commit/fe22615b7fa17d3c20ac26d6f82097917c9b63f6))
+# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)
+### Bug Fixes
-# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)
+- **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))
+- **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))
+- Freeze the resolver context ([#2685](https://github.com/feathersjs/feathers/issues/2685)) ([247dccb](https://github.com/feathersjs/feathers/commit/247dccb2eb72551962030321cb1c0ecb11b0181e))
+- **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))
-**Note:** Version bump only for package feathers
+### Features
+- **cli:** Add support for Prettier ([#2684](https://github.com/feathersjs/feathers/issues/2684)) ([83aa8f9](https://github.com/feathersjs/feathers/commit/83aa8f9f212cb122d831dca8858852b0ac9b4da8))
+- **cli:** Improve generated application folder structure ([#2678](https://github.com/feathersjs/feathers/issues/2678)) ([d114557](https://github.com/feathersjs/feathers/commit/d114557721e73d6302aa88c11e3726dbcbd5c92b))
+# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)
+### Bug Fixes
+- **cli:** Fix compilation folders that got mixed up ([fc4cb74](https://github.com/feathersjs/feathers/commit/fc4cb742f7f9164096d9319b13dfaaa5f54686a6))
-# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)
+# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)
-**Note:** Version bump only for package feathers
+### Bug Fixes
+- **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))
+# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)
+### Bug Fixes
+- **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))
+- **authentication:** Add safe dispatch data for authentication requests ([#2662](https://github.com/feathersjs/feathers/issues/2662)) ([d8104a1](https://github.com/feathersjs/feathers/commit/d8104a19ee9181e6a5ea81014af29ff9a3c28a8a))
+- **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))
-# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)
+### Features
+- **authentication-local:** Add passwordHash property resolver ([#2660](https://github.com/feathersjs/feathers/issues/2660)) ([b41279b](https://github.com/feathersjs/feathers/commit/b41279b55eea3771a6fa4983a37be2413287bbc6))
+- **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))
+- **cli:** Add hook generator ([#2667](https://github.com/feathersjs/feathers/issues/2667)) ([24e4bc0](https://github.com/feathersjs/feathers/commit/24e4bc04a67fadee0e6a96a8389d788faba5c305))
+- **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))
+- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))
+- **cli:** Initial Feathers v5 CLI and Pinion generator ([#2578](https://github.com/feathersjs/feathers/issues/2578)) ([7f59ae7](https://github.com/feathersjs/feathers/commit/7f59ae7f1471895ba8a82aa4702f1a23f71b7682))
+- **knex:** Add KnexJS SQL database adapter to core ([#2671](https://github.com/feathersjs/feathers/issues/2671)) ([9380fff](https://github.com/feathersjs/feathers/commit/9380fff58596e8bb90b8bb098d2795b7eadfec20))
-### Bug Fixes
+# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)
-* **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))
+### Bug Fixes
+- **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))
+- **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))
+- **schema:** remove `default` from queryProperty schemas ([#2646](https://github.com/feathersjs/feathers/issues/2646)) ([940a2b6](https://github.com/feathersjs/feathers/commit/940a2b6868d2f77f81edb1661f6417ec2ea6e372))
### Features
-* **schema:** Allow resolvers to validate a schema ([#2465](https://github.com/feathersjs/feathers/issues/2465)) ([7d9590b](https://github.com/feathersjs/feathers/commit/7d9590bbe12b94b8b5a7987684f5d4968e426481))
-
+- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))
+- **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))
+# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)
+### Bug Fixes
+- **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))
-# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)
-
+# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)
### Bug Fixes
-* **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))
-
+- **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))
+- **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))
+- **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))
+- **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))
### Features
-* **schema:** Initial version of schema definitions and resolvers ([#2441](https://github.com/feathersjs/feathers/issues/2441)) ([c57a5cd](https://github.com/feathersjs/feathers/commit/c57a5cd56699a121647be4506d8f967e6d72ecae))
+- **schema:** Add resolveAll hook ([#2643](https://github.com/feathersjs/feathers/issues/2643)) ([85527d7](https://github.com/feathersjs/feathers/commit/85527d71cb78852880696e5d96abdcdf24593934))
+- **schema:** Add resolver for safe external data dispatching ([#2641](https://github.com/feathersjs/feathers/issues/2641)) ([72b980e](https://github.com/feathersjs/feathers/commit/72b980e05631136d30c8f1468dee45ec6a8d2503))
+- **schema:** Add schema resolver converter functionality ([#2640](https://github.com/feathersjs/feathers/issues/2640)) ([26d9e05](https://github.com/feathersjs/feathers/commit/26d9e05327d6e0144466cd57d6fcc11ac7ecb06a))
+# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)
+### Bug Fixes
+- **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))
+- **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))
+- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))
+### Features
-# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)
+- **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))
-**Note:** Version bump only for package feathers
+# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)
+### Bug Fixes
+- **adapter-commons:** Clarify adapter query filtering ([#2607](https://github.com/feathersjs/feathers/issues/2607)) ([2dac771](https://github.com/feathersjs/feathers/commit/2dac771b0a3298d6dd25994d05186701b0617718))
+- **adapter-tests:** Ensure multi tests can run standalone ([#2608](https://github.com/feathersjs/feathers/issues/2608)) ([d7243f2](https://github.com/feathersjs/feathers/commit/d7243f20e84d9dde428ad8dfc7f48388ca569e6e))
+- **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))
+- **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))
+- **client:** Fix @feathersjs/client types field ([#2596](https://github.com/feathersjs/feathers/issues/2596)) ([d719f54](https://github.com/feathersjs/feathers/commit/d719f54daee63daf9ed5cc762626ca15131086de))
+- **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))
+- **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))
+### Features
+- **mongodb:** Add feathers-mongodb adapter as @feathersjs/mongodb ([#2610](https://github.com/feathersjs/feathers/issues/2610)) ([6d43734](https://github.com/feathersjs/feathers/commit/6d43734a53db02c435cafc52a22dca414e5d0940))
+- **schema:** Allow hooks to run resolvers in sequence ([#2609](https://github.com/feathersjs/feathers/issues/2609)) ([d85c507](https://github.com/feathersjs/feathers/commit/d85c507c76d07e48fc8e7e28ff7de0ef435e0ef8))
+- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))
+- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))
-# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)
+### BREAKING CHANGES
-**Note:** Version bump only for package feathers
+- **adapter-commons:** Changes the common adapter base class to use `sanitizeQuery` and `sanitizeData`
+# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)
+### Bug Fixes
+- **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))
+- **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))
+- **schema:** result resolver correctly resolves paginated find result ([#2594](https://github.com/feathersjs/feathers/issues/2594)) ([6511e45](https://github.com/feathersjs/feathers/commit/6511e45bd0624f1a629530719709f4b27fecbe0b))
+### Features
-# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)
+- **authentication:** Add setup method for auth strategies ([#1611](https://github.com/feathersjs/feathers/issues/1611)) ([a3c3581](https://github.com/feathersjs/feathers/commit/a3c35814dccdbbf6de96f04f60b226ce206c6dbe))
+- **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))
+- **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))
+- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))
+- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))
+- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))
+# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)
### Bug Fixes
-* **core:** Clean up readme ([eb3b4f2](https://github.com/feathersjs/feathers/commit/eb3b4f248c0816c92a2300cceed18a6f2518508a))
-* **core:** Set version back to development ([b328767](https://github.com/feathersjs/feathers/commit/b3287676cd773e164fd646ba4cffbf81983a9157))
+- **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))
+- **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))
+- **queryProperty:** allow compound oneOf ([#2545](https://github.com/feathersjs/feathers/issues/2545)) ([3077d2d](https://github.com/feathersjs/feathers/commit/3077d2d896a38d579ce4d5b530e21ad332bcf221))
+- **schema:** Properly handle resolver errors ([#2540](https://github.com/feathersjs/feathers/issues/2540)) ([31fbdff](https://github.com/feathersjs/feathers/commit/31fbdff8bd848ac7e0eda56e307ac34b1bfcf17f))
+# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)
+### Bug Fixes
+- **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))
+- **schema:** Do not error for schemas without properties ([#2519](https://github.com/feathersjs/feathers/issues/2519)) ([96fdb47](https://github.com/feathersjs/feathers/commit/96fdb47d45fd88a8039aa9cc9ec8aebd98672b95))
+- **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))
+### Features
-# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)
+- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))
+- **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))
+- **schema:** Improve schema typing, validation and extensibility ([#2521](https://github.com/feathersjs/feathers/issues/2521)) ([8c1b350](https://github.com/feathersjs/feathers/commit/8c1b35052792e82d13be03c06583534284fbae82))
+# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)
### Bug Fixes
-* **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))
-
-
-
+- **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))
+- **adapter-commons:** Fix sorting for embedded objects ([#2488](https://github.com/feathersjs/feathers/issues/2488)) ([9c22f70](https://github.com/feathersjs/feathers/commit/9c22f70a838cb6341775d91705a7527c8fc5590e))
+- missing express types for Request, Response ([#2498](https://github.com/feathersjs/feathers/issues/2498)) ([ee67131](https://github.com/feathersjs/feathers/commit/ee67131bbaa24c54d3d781bdf8820015759ac488))
+- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))
+### Features
-# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)
+- **authentication-oauth:** Allow dynamic oAuth redirect ([#2469](https://github.com/feathersjs/feathers/issues/2469)) ([b7143d4](https://github.com/feathersjs/feathers/commit/b7143d4c0fbe961e714f79512be04449b9bbd7d9))
+- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))
+- **core:** Improve legacy hooks integration ([08c8b40](https://github.com/feathersjs/feathers/commit/08c8b40999bf3889c61a4d4fad97a2c4f78bafc9))
+- **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))
+# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)
-### Bug Fixes
+**Note:** Version bump only for package feathers
-* **authentication-oauth:** Omit query from internal calls ([#2398](https://github.com/feathersjs/feathers/issues/2398)) ([04c7c83](https://github.com/feathersjs/feathers/commit/04c7c83eeaa6a7466c84b958071b468ed42f0b0f))
-* **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))
-* **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))
-* **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))
-* Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))
+# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)
+**Note:** Version bump only for package feathers
-### Features
+# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)
-* **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))
-* Support being a built-in CodeSandbox sandbox ([#2381](https://github.com/feathersjs/feathers/issues/2381)) ([a2ac25a](https://github.com/feathersjs/feathers/commit/a2ac25a26e80530f7c50b88ef15eef46ee2b0634))
-* **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))
+**Note:** Version bump only for package feathers
+# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)
+### Bug Fixes
+- **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))
+### Features
-# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)
+- **schema:** Allow resolvers to validate a schema ([#2465](https://github.com/feathersjs/feathers/issues/2465)) ([7d9590b](https://github.com/feathersjs/feathers/commit/7d9590bbe12b94b8b5a7987684f5d4968e426481))
+# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)
### Bug Fixes
-* **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))
-* **typescript:** Move Paginated type back for better compatibility ([#2350](https://github.com/feathersjs/feathers/issues/2350)) ([2917d05](https://github.com/feathersjs/feathers/commit/2917d05fffb4716d3c4cdaa5ac6a1aee0972e8a6))
-
+- **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))
### Features
-* **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))
-
+- **schema:** Initial version of schema definitions and resolvers ([#2441](https://github.com/feathersjs/feathers/issues/2441)) ([c57a5cd](https://github.com/feathersjs/feathers/commit/c57a5cd56699a121647be4506d8f967e6d72ecae))
+# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)
+**Note:** Version bump only for package feathers
+# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)
-# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)
+**Note:** Version bump only for package feathers
+# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)
### Bug Fixes
-* **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))
+- **core:** Clean up readme ([eb3b4f2](https://github.com/feathersjs/feathers/commit/eb3b4f248c0816c92a2300cceed18a6f2518508a))
+- **core:** Set version back to development ([b328767](https://github.com/feathersjs/feathers/commit/b3287676cd773e164fd646ba4cffbf81983a9157))
+# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)
-### Features
-
-* **deno:** Feathers core build for Deno ([#2299](https://github.com/feathersjs/feathers/issues/2299)) ([dece8fb](https://github.com/feathersjs/feathers/commit/dece8fbc0e7601f1505ce8bbb1e4e69cc26e8f98))
-* **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))
+### Bug Fixes
+- **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))
+# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)
+### Bug Fixes
+- **authentication-oauth:** Omit query from internal calls ([#2398](https://github.com/feathersjs/feathers/issues/2398)) ([04c7c83](https://github.com/feathersjs/feathers/commit/04c7c83eeaa6a7466c84b958071b468ed42f0b0f))
+- **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))
+- **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))
+- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))
+- Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))
-# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)
+### Features
-**Note:** Version bump only for package feathers
+- **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))
+- Support being a built-in CodeSandbox sandbox ([#2381](https://github.com/feathersjs/feathers/issues/2381)) ([a2ac25a](https://github.com/feathersjs/feathers/commit/a2ac25a26e80530f7c50b88ef15eef46ee2b0634))
+- **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))
+# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)
+### Bug Fixes
+- **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))
+- **typescript:** Move Paginated type back for better compatibility ([#2350](https://github.com/feathersjs/feathers/issues/2350)) ([2917d05](https://github.com/feathersjs/feathers/commit/2917d05fffb4716d3c4cdaa5ac6a1aee0972e8a6))
+### Features
-# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)
+- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))
+# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)
### Bug Fixes
-* **adapter-tests:** Add test that verified paginated total ([#2273](https://github.com/feathersjs/feathers/issues/2273)) ([879bd6b](https://github.com/feathersjs/feathers/commit/879bd6b24f42e04eeeeba110ddddda3e1e1dea34))
-* **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))
-* **feathers:** Always enable hooks on default service methods ([#2275](https://github.com/feathersjs/feathers/issues/2275)) ([827cc9b](https://github.com/feathersjs/feathers/commit/827cc9b752eecdaf63605d7dffd86f531b7e4af3))
-
+- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))
### Features
-* **adapter-commons:** Added mongoDB like search in embedded objects ([687e3c7](https://github.com/feathersjs/feathers/commit/687e3c7c36904221b2707d0220c0893e3cb1faa9))
-
-
-
+- **deno:** Feathers core build for Deno ([#2299](https://github.com/feathersjs/feathers/issues/2299)) ([dece8fb](https://github.com/feathersjs/feathers/commit/dece8fbc0e7601f1505ce8bbb1e4e69cc26e8f98))
+- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))
+# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)
-# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)
+**Note:** Version bump only for package feathers
+# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)
### Bug Fixes
-* **adapter-commons:** Always respect paginate.max ([#2267](https://github.com/feathersjs/feathers/issues/2267)) ([f588257](https://github.com/feathersjs/feathers/commit/f5882575536624ed3a32bb6e3ff1919fa17e366d))
-* **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))
-* Resolve some type problems ([#2260](https://github.com/feathersjs/feathers/issues/2260)) ([a3d75fa](https://github.com/feathersjs/feathers/commit/a3d75fa29490e8a19412a12bc993ee7bb573068f))
-* Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))
-* **adapter-commons:** Return missing overloads ([#2203](https://github.com/feathersjs/feathers/issues/2203)) ([bbe7e2a](https://github.com/feathersjs/feathers/commit/bbe7e2a131633e9a6e7aac7f7fa02a312bca63c7))
-* **socketio-client:** Fix client transport-commons reference ([#2164](https://github.com/feathersjs/feathers/issues/2164)) ([3a42c54](https://github.com/feathersjs/feathers/commit/3a42c544058456b19c7e21827226541bfa6ad621))
-
+- **adapter-tests:** Add test that verified paginated total ([#2273](https://github.com/feathersjs/feathers/issues/2273)) ([879bd6b](https://github.com/feathersjs/feathers/commit/879bd6b24f42e04eeeeba110ddddda3e1e1dea34))
+- **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))
+- **feathers:** Always enable hooks on default service methods ([#2275](https://github.com/feathersjs/feathers/issues/2275)) ([827cc9b](https://github.com/feathersjs/feathers/commit/827cc9b752eecdaf63605d7dffd86f531b7e4af3))
### Features
-* **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))
-* Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))
-* Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))
-* **authentication-client:** Throw separate OauthError in authentication client ([#2189](https://github.com/feathersjs/feathers/issues/2189)) ([fa45ec5](https://github.com/feathersjs/feathers/commit/fa45ec520b21834e103e6fe4200b06dced56c0e6))
-* **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))
-* **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))
+- **adapter-commons:** Added mongoDB like search in embedded objects ([687e3c7](https://github.com/feathersjs/feathers/commit/687e3c7c36904221b2707d0220c0893e3cb1faa9))
+# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)
-### BREAKING CHANGES
+### Bug Fixes
-* **core:** Services no longer extend Uberproto objects and
-`service.mixin()` is no longer available.
+- **adapter-commons:** Always respect paginate.max ([#2267](https://github.com/feathersjs/feathers/issues/2267)) ([f588257](https://github.com/feathersjs/feathers/commit/f5882575536624ed3a32bb6e3ff1919fa17e366d))
+- **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))
+- Resolve some type problems ([#2260](https://github.com/feathersjs/feathers/issues/2260)) ([a3d75fa](https://github.com/feathersjs/feathers/commit/a3d75fa29490e8a19412a12bc993ee7bb573068f))
+- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))
+- **adapter-commons:** Return missing overloads ([#2203](https://github.com/feathersjs/feathers/issues/2203)) ([bbe7e2a](https://github.com/feathersjs/feathers/commit/bbe7e2a131633e9a6e7aac7f7fa02a312bca63c7))
+- **socketio-client:** Fix client transport-commons reference ([#2164](https://github.com/feathersjs/feathers/issues/2164)) ([3a42c54](https://github.com/feathersjs/feathers/commit/3a42c544058456b19c7e21827226541bfa6ad621))
+### Features
+- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))
+- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))
+- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))
+- **authentication-client:** Throw separate OauthError in authentication client ([#2189](https://github.com/feathersjs/feathers/issues/2189)) ([fa45ec5](https://github.com/feathersjs/feathers/commit/fa45ec520b21834e103e6fe4200b06dced56c0e6))
+- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))
+- **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))
+### BREAKING CHANGES
+- **core:** Services no longer extend Uberproto objects and
+ `service.mixin()` is no longer available.
# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)
-
### Features
-* **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))
-
-
+- **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))
# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)
-
### Bug Fixes
-* **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))
-
+- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))
### chore
-* **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))
-* **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)
-
+- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))
+- **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)
### Features
-* **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))
-* **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))
-* **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))
-
+- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))
+- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))
+- **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))
### BREAKING CHANGES
-* **configuration:** Falls back to node-config instead of adding additional
-functionality like path replacements and automatic environment variable insertion.
-* **transport-commons:** Removes the old message format and client service timeout
-* **package:** Remove primus packages to be moved into the ecosystem.
-
-
-
-
+- **configuration:** Falls back to node-config instead of adding additional
+ functionality like path replacements and automatic environment variable insertion.
+- **transport-commons:** Removes the old message format and client service timeout
+- **package:** Remove primus packages to be moved into the ecosystem.
# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)
### Bug Fixes
-* **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))
-* **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))
-
+- **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))
+- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))
### chore
-* **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))
-* **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)
-
+- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))
+- **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)
### Features
-* **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))
-* **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))
-* **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))
-
+- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))
+- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))
+- **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))
### BREAKING CHANGES
-* **configuration:** Falls back to node-config instead of adding additional
-functionality like path replacements and automatic environment variable insertion.
-* **transport-commons:** Removes the old message format and client service timeout
-* **package:** Remove primus packages to be moved into the ecosystem.
-
-
+- **configuration:** Falls back to node-config instead of adding additional
+ functionality like path replacements and automatic environment variable insertion.
+- **transport-commons:** Removes the old message format and client service timeout
+- **package:** Remove primus packages to be moved into the ecosystem.
## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)
-
### Bug Fixes
-* **authentication-client:** Allow reAuthentication using specific strategy ([#2140](https://github.com/feathersjs/feathers/issues/2140)) ([2a2bbf7](https://github.com/feathersjs/feathers/commit/2a2bbf7f8ee6d32b9fac8afab3421286b06e6443))
-* **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))
-* **typescript:** Fix `data` property definition in @feathersjs/errors ([#2018](https://github.com/feathersjs/feathers/issues/2018)) ([ef1398c](https://github.com/feathersjs/feathers/commit/ef1398cd5b19efa50929e8c9511ca5684a18997f))
-
-
-
-
+- **authentication-client:** Allow reAuthentication using specific strategy ([#2140](https://github.com/feathersjs/feathers/issues/2140)) ([2a2bbf7](https://github.com/feathersjs/feathers/commit/2a2bbf7f8ee6d32b9fac8afab3421286b06e6443))
+- **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))
+- **typescript:** Fix `data` property definition in @feathersjs/errors ([#2018](https://github.com/feathersjs/feathers/issues/2018)) ([ef1398c](https://github.com/feathersjs/feathers/commit/ef1398cd5b19efa50929e8c9511ca5684a18997f))
## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)
-
### Bug Fixes
-* **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))
-* **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))
-* **package:** Fix clean script in non Unix environments ([#2110](https://github.com/feathersjs/feathers/issues/2110)) ([09b62c0](https://github.com/feathersjs/feathers/commit/09b62c0c7e636caf620904ba87d61f168a020f05))
-* **typescript:** Add user property to the Params. ([#2090](https://github.com/feathersjs/feathers/issues/2090)) ([1e94265](https://github.com/feathersjs/feathers/commit/1e942651fbaaf07fc66c159225fbc992a0174bf4))
-
-
-
-
+- **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))
+- **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))
+- **package:** Fix clean script in non Unix environments ([#2110](https://github.com/feathersjs/feathers/issues/2110)) ([09b62c0](https://github.com/feathersjs/feathers/commit/09b62c0c7e636caf620904ba87d61f168a020f05))
+- **typescript:** Add user property to the Params. ([#2090](https://github.com/feathersjs/feathers/issues/2090)) ([1e94265](https://github.com/feathersjs/feathers/commit/1e942651fbaaf07fc66c159225fbc992a0174bf4))
## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)
-
### Bug Fixes
-* **authentication-local:** Keep non-objects in protect hook ([#2085](https://github.com/feathersjs/feathers/issues/2085)) ([5a65e2e](https://github.com/feathersjs/feathers/commit/5a65e2e6cee0a15614f23ee2e0d3c25d3365027d))
-* **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))
-* **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))
-* **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))
-
-
-
-
+- **authentication-local:** Keep non-objects in protect hook ([#2085](https://github.com/feathersjs/feathers/issues/2085)) ([5a65e2e](https://github.com/feathersjs/feathers/commit/5a65e2e6cee0a15614f23ee2e0d3c25d3365027d))
+- **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))
+- **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))
+- **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))
## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)
-
-* **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))
-
-
-
-
+- **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))
## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)
-
### Bug Fixes
-* **authentication:** Add JWT getEntityQuery ([#2013](https://github.com/feathersjs/feathers/issues/2013)) ([e0e7fb5](https://github.com/feathersjs/feathers/commit/e0e7fb5162940fe776731283b40026c61d9c8a33))
-* **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))
-
-
-
-
+- **authentication:** Add JWT getEntityQuery ([#2013](https://github.com/feathersjs/feathers/issues/2013)) ([e0e7fb5](https://github.com/feathersjs/feathers/commit/e0e7fb5162940fe776731283b40026c61d9c8a33))
+- **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))
## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)
-
### Bug Fixes
-* **authentication:** Omit query in JWT strategy ([#2011](https://github.com/feathersjs/feathers/issues/2011)) ([04ce7e9](https://github.com/feathersjs/feathers/commit/04ce7e98515fe9d495cd0e83e0da097e9bcd7382))
-
-
-
-
+- **authentication:** Omit query in JWT strategy ([#2011](https://github.com/feathersjs/feathers/issues/2011)) ([04ce7e9](https://github.com/feathersjs/feathers/commit/04ce7e98515fe9d495cd0e83e0da097e9bcd7382))
## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)
-
### Bug Fixes
-* **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))
-* **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))
-* **typescript:** add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972)) ([ef55af0](https://github.com/feathersjs/feathers/commit/ef55af088d05d9d36aba9d9f8d6c2c908a4f20dd))
-
-
-
-
+- **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))
+- **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))
+- **typescript:** add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972)) ([ef55af0](https://github.com/feathersjs/feathers/commit/ef55af088d05d9d36aba9d9f8d6c2c908a4f20dd))
## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)
-
### Bug Fixes
-* **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))
-* **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))
-
-
-
-
+- **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))
+- **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))
## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)
-
### Bug Fixes
-* **authentication:** Remove entity from connection information on logout ([#1889](https://github.com/feathersjs/feathers/issues/1889)) ([b062753](https://github.com/feathersjs/feathers/commit/b0627530d61babe15dd84369d3093ccae4b780ca))
-* **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))
-* **errors:** Add 410 Gone to errors ([#1849](https://github.com/feathersjs/feathers/issues/1849)) ([6801428](https://github.com/feathersjs/feathers/commit/6801428f8fd17dbfebcdb6f1b0cd01433a4033dc))
-* **typescript:** Add type keys to service pagination options. ([#1888](https://github.com/feathersjs/feathers/issues/1888)) ([859c601](https://github.com/feathersjs/feathers/commit/859c601519c7cb399e8b1667bb50073466812d5c))
-* **typescript:** Use stricter type for HookContext 'method' prop ([#1896](https://github.com/feathersjs/feathers/issues/1896)) ([24a41b7](https://github.com/feathersjs/feathers/commit/24a41b74486ddadccad18f3ae63afdac5bd373c7))
-
-
-
-
+- **authentication:** Remove entity from connection information on logout ([#1889](https://github.com/feathersjs/feathers/issues/1889)) ([b062753](https://github.com/feathersjs/feathers/commit/b0627530d61babe15dd84369d3093ccae4b780ca))
+- **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))
+- **errors:** Add 410 Gone to errors ([#1849](https://github.com/feathersjs/feathers/issues/1849)) ([6801428](https://github.com/feathersjs/feathers/commit/6801428f8fd17dbfebcdb6f1b0cd01433a4033dc))
+- **typescript:** Add type keys to service pagination options. ([#1888](https://github.com/feathersjs/feathers/issues/1888)) ([859c601](https://github.com/feathersjs/feathers/commit/859c601519c7cb399e8b1667bb50073466812d5c))
+- **typescript:** Use stricter type for HookContext 'method' prop ([#1896](https://github.com/feathersjs/feathers/issues/1896)) ([24a41b7](https://github.com/feathersjs/feathers/commit/24a41b74486ddadccad18f3ae63afdac5bd373c7))
## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)
-
### Bug Fixes
-* Updated typings for express middleware ([#1839](https://github.com/feathersjs/feathers/issues/1839)) ([6b8e897](https://github.com/feathersjs/feathers/commit/6b8e8971a9dbb08913edd1be48826624645d9dc1))
-* **authentication:** Improve JWT strategy configuration error message ([#1844](https://github.com/feathersjs/feathers/issues/1844)) ([2c771db](https://github.com/feathersjs/feathers/commit/2c771dbb22d53d4f7de3c3f514e57afa1a186322))
-* **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))
-* **test:** typo in password ([#1797](https://github.com/feathersjs/feathers/issues/1797)) ([dfba6ec](https://github.com/feathersjs/feathers/commit/dfba6ec2f21adf3aa739218cf870eaaaa5df6e9c))
-* **typescript:** Make HookMap and HookObject generics. ([#1815](https://github.com/feathersjs/feathers/issues/1815)) ([d10145d](https://github.com/feathersjs/feathers/commit/d10145d91a09aef7bce5af80805a3c0fa9d94f26))
-
-
-
-
+- Updated typings for express middleware ([#1839](https://github.com/feathersjs/feathers/issues/1839)) ([6b8e897](https://github.com/feathersjs/feathers/commit/6b8e8971a9dbb08913edd1be48826624645d9dc1))
+- **authentication:** Improve JWT strategy configuration error message ([#1844](https://github.com/feathersjs/feathers/issues/1844)) ([2c771db](https://github.com/feathersjs/feathers/commit/2c771dbb22d53d4f7de3c3f514e57afa1a186322))
+- **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))
+- **test:** typo in password ([#1797](https://github.com/feathersjs/feathers/issues/1797)) ([dfba6ec](https://github.com/feathersjs/feathers/commit/dfba6ec2f21adf3aa739218cf870eaaaa5df6e9c))
+- **typescript:** Make HookMap and HookObject generics. ([#1815](https://github.com/feathersjs/feathers/issues/1815)) ([d10145d](https://github.com/feathersjs/feathers/commit/d10145d91a09aef7bce5af80805a3c0fa9d94f26))
## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)
**Note:** Version bump only for package feathers
-
-
-
-
# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)
-
### Bug Fixes
-* Add `params.authentication` type, remove `hook.connection` type ([#1732](https://github.com/feathersjs/feathers/issues/1732)) ([d46b7b2](https://github.com/feathersjs/feathers/commit/d46b7b2abac8862c0e4dbfce20d71b8b8a96692f))
-
+- Add `params.authentication` type, remove `hook.connection` type ([#1732](https://github.com/feathersjs/feathers/issues/1732)) ([d46b7b2](https://github.com/feathersjs/feathers/commit/d46b7b2abac8862c0e4dbfce20d71b8b8a96692f))
### Features
-* **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))
-* **rest-client:** Allow for customising rest clients ([#1780](https://github.com/feathersjs/feathers/issues/1780)) ([c5cfec7](https://github.com/feathersjs/feathers/commit/c5cfec7a4aafcaffaab0cdacb9b5d297ff20320f))
-
-
-
-
+- **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))
+- **rest-client:** Allow for customising rest clients ([#1780](https://github.com/feathersjs/feathers/issues/1780)) ([c5cfec7](https://github.com/feathersjs/feathers/commit/c5cfec7a4aafcaffaab0cdacb9b5d297ff20320f))
## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)
-
### Bug Fixes
-* **adapter-commons:** Filter arrays in queries ([#1724](https://github.com/feathersjs/feathers/issues/1724)) ([872b669](https://github.com/feathersjs/feathers/commit/872b66906a806ab92ca41b5f6f504ff0af1ce79e))
-
-
-
-
+- **adapter-commons:** Filter arrays in queries ([#1724](https://github.com/feathersjs/feathers/issues/1724)) ([872b669](https://github.com/feathersjs/feathers/commit/872b66906a806ab92ca41b5f6f504ff0af1ce79e))
## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)
-
### Bug Fixes
-* Gracefully handle errors in publishers ([#1710](https://github.com/feathersjs/feathers/issues/1710)) ([0616306](https://github.com/feathersjs/feathers/commit/061630696762e9dbf1dc4e738094992ba16989fc))
-
-
-
-
+- Gracefully handle errors in publishers ([#1710](https://github.com/feathersjs/feathers/issues/1710)) ([0616306](https://github.com/feathersjs/feathers/commit/061630696762e9dbf1dc4e738094992ba16989fc))
# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)
-
### Bug Fixes
-* **authentication-client:** Reset authentication promise on socket disconnect ([#1696](https://github.com/feathersjs/feathers/issues/1696)) ([3951626](https://github.com/feathersjs/feathers/commit/395162633ff22e95833a3c2900cb9464bb5b056f))
-* **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))
-* **rest-client:** Allow to customize getting the query ([#1594](https://github.com/feathersjs/feathers/issues/1594)) ([5f21272](https://github.com/feathersjs/feathers/commit/5f212729849414c4da6f0d51edd1986feca992ee))
-* **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))
-* **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))
-
+- **authentication-client:** Reset authentication promise on socket disconnect ([#1696](https://github.com/feathersjs/feathers/issues/1696)) ([3951626](https://github.com/feathersjs/feathers/commit/395162633ff22e95833a3c2900cb9464bb5b056f))
+- **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))
+- **rest-client:** Allow to customize getting the query ([#1594](https://github.com/feathersjs/feathers/issues/1594)) ([5f21272](https://github.com/feathersjs/feathers/commit/5f212729849414c4da6f0d51edd1986feca992ee))
+- **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))
+- **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))
### Features
-* **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))
-* **authentication-oauth:** Set oAuth redirect URL dynamically ([#1608](https://github.com/feathersjs/feathers/issues/1608)) ([1293e08](https://github.com/feathersjs/feathers/commit/1293e088abbb3d23f4a44680836645a8049ceaae))
-
-
-
-
+- **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))
+- **authentication-oauth:** Set oAuth redirect URL dynamically ([#1608](https://github.com/feathersjs/feathers/issues/1608)) ([1293e08](https://github.com/feathersjs/feathers/commit/1293e088abbb3d23f4a44680836645a8049ceaae))
## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)
-
### Bug Fixes
-* **authentication:** Retain object references in authenticate hook ([#1675](https://github.com/feathersjs/feathers/issues/1675)) ([e1939be](https://github.com/feathersjs/feathers/commit/e1939be19d4e79d3f5e2fe69ba894a11c627ae99))
-* **authentication-oauth:** Allow hash based redirects ([#1676](https://github.com/feathersjs/feathers/issues/1676)) ([ffe7cf3](https://github.com/feathersjs/feathers/commit/ffe7cf3fbb4e62d7689065cf7b61f25f602ce8cf))
-
-
-
-
+- **authentication:** Retain object references in authenticate hook ([#1675](https://github.com/feathersjs/feathers/issues/1675)) ([e1939be](https://github.com/feathersjs/feathers/commit/e1939be19d4e79d3f5e2fe69ba894a11c627ae99))
+- **authentication-oauth:** Allow hash based redirects ([#1676](https://github.com/feathersjs/feathers/issues/1676)) ([ffe7cf3](https://github.com/feathersjs/feathers/commit/ffe7cf3fbb4e62d7689065cf7b61f25f602ce8cf))
## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)
**Note:** Version bump only for package feathers
-
-
-
-
## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)
-
### Bug Fixes
-* Add jsonwebtoken TypeScript type dependency ([317c80a](https://github.com/feathersjs/feathers/commit/317c80a9205e8853bb830a12c3aa1a19e95f9abc))
-* 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))
-* Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))
-
-
-
-
+- Add jsonwebtoken TypeScript type dependency ([317c80a](https://github.com/feathersjs/feathers/commit/317c80a9205e8853bb830a12c3aa1a19e95f9abc))
+- 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))
+- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))
## [4.3.8](https://github.com/feathersjs/feathers/compare/v4.3.7...v4.3.8) (2019-10-14)
-
### Bug Fixes
-* Remove adapter commons type alternatives ([#1620](https://github.com/feathersjs/feathers/issues/1620)) ([c9f3086](https://github.com/feathersjs/feathers/commit/c9f3086344420b57dbce7c4169cf550c97509f0d))
-
-
-
-
+- Remove adapter commons type alternatives ([#1620](https://github.com/feathersjs/feathers/issues/1620)) ([c9f3086](https://github.com/feathersjs/feathers/commit/c9f3086344420b57dbce7c4169cf550c97509f0d))
## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)
-
### Bug Fixes
-* Improve authentication client default storage initialization ([#1613](https://github.com/feathersjs/feathers/issues/1613)) ([d7f5107](https://github.com/feathersjs/feathers/commit/d7f5107ef76297b4ca6db580afc5e2b372f5ee4d))
-* improve Service and AdapterService types ([#1567](https://github.com/feathersjs/feathers/issues/1567)) ([baad6a2](https://github.com/feathersjs/feathers/commit/baad6a26f0f543b712ccb40359b3933ad3a21392))
-* make __hooks writable and configurable ([#1520](https://github.com/feathersjs/feathers/issues/1520)) ([1c6c374](https://github.com/feathersjs/feathers/commit/1c6c3742ecf1cb813be56074da89e6736d03ffe8))
-* Typings for express request and response properties ([#1609](https://github.com/feathersjs/feathers/issues/1609)) ([38cf8c9](https://github.com/feathersjs/feathers/commit/38cf8c950c1a4fb4a6d78d68d70e7fdd63b71c3c))
-
-
-
-
+- Improve authentication client default storage initialization ([#1613](https://github.com/feathersjs/feathers/issues/1613)) ([d7f5107](https://github.com/feathersjs/feathers/commit/d7f5107ef76297b4ca6db580afc5e2b372f5ee4d))
+- improve Service and AdapterService types ([#1567](https://github.com/feathersjs/feathers/issues/1567)) ([baad6a2](https://github.com/feathersjs/feathers/commit/baad6a26f0f543b712ccb40359b3933ad3a21392))
+- make \_\_hooks writable and configurable ([#1520](https://github.com/feathersjs/feathers/issues/1520)) ([1c6c374](https://github.com/feathersjs/feathers/commit/1c6c3742ecf1cb813be56074da89e6736d03ffe8))
+- Typings for express request and response properties ([#1609](https://github.com/feathersjs/feathers/issues/1609)) ([38cf8c9](https://github.com/feathersjs/feathers/commit/38cf8c950c1a4fb4a6d78d68d70e7fdd63b71c3c))
## [4.3.6](https://github.com/feathersjs/feathers/compare/v4.3.5...v4.3.6) (2019-10-07)
-
### Bug Fixes
-* Check query for NaN ([#1607](https://github.com/feathersjs/feathers/issues/1607)) ([f1a781f](https://github.com/feathersjs/feathers/commit/f1a781f))
-
-
-
-
+- Check query for NaN ([#1607](https://github.com/feathersjs/feathers/issues/1607)) ([f1a781f](https://github.com/feathersjs/feathers/commit/f1a781f))
## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)
-
### Bug Fixes
-* Authentication type improvements and timeout fix ([#1605](https://github.com/feathersjs/feathers/issues/1605)) ([19854d3](https://github.com/feathersjs/feathers/commit/19854d3))
-* 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))
-* 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))
-
-
-
-
+- Authentication type improvements and timeout fix ([#1605](https://github.com/feathersjs/feathers/issues/1605)) ([19854d3](https://github.com/feathersjs/feathers/commit/19854d3))
+- 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))
+- 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))
## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)
-
### Bug Fixes
-* Reset version number after every publish ([#1596](https://github.com/feathersjs/feathers/issues/1596)) ([f24f82f](https://github.com/feathersjs/feathers/commit/f24f82f))
-* Typing improvements ([#1580](https://github.com/feathersjs/feathers/issues/1580)) ([7818aec](https://github.com/feathersjs/feathers/commit/7818aec))
-
-
-
-
+- Reset version number after every publish ([#1596](https://github.com/feathersjs/feathers/issues/1596)) ([f24f82f](https://github.com/feathersjs/feathers/commit/f24f82f))
+- Typing improvements ([#1580](https://github.com/feathersjs/feathers/issues/1580)) ([7818aec](https://github.com/feathersjs/feathers/commit/7818aec))
## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)
-
### Bug Fixes
-* check for undefined access token ([#1571](https://github.com/feathersjs/feathers/issues/1571)) ([976369d](https://github.com/feathersjs/feathers/commit/976369d))
-* Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))
-
-
-
-
+- check for undefined access token ([#1571](https://github.com/feathersjs/feathers/issues/1571)) ([976369d](https://github.com/feathersjs/feathers/commit/976369d))
+- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))
## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)
-
### Bug Fixes
-* Add info to express error handler logger type ([#1557](https://github.com/feathersjs/feathers/issues/1557)) ([3e1d26c](https://github.com/feathersjs/feathers/commit/3e1d26c))
-* 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)
-
-
-
-
+- Add info to express error handler logger type ([#1557](https://github.com/feathersjs/feathers/issues/1557)) ([3e1d26c](https://github.com/feathersjs/feathers/commit/3e1d26c))
+- 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)
## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)
-
### Bug Fixes
-* Fix regression in transport commons ([#1551](https://github.com/feathersjs/feathers/issues/1551)) ([ed9e934](https://github.com/feathersjs/feathers/commit/ed9e934))
-* Omit standard protocol ports from the default hostname ([#1543](https://github.com/feathersjs/feathers/issues/1543)) ([ef16d29](https://github.com/feathersjs/feathers/commit/ef16d29))
-* Use long-timeout for JWT expiration timers ([#1552](https://github.com/feathersjs/feathers/issues/1552)) ([65637ec](https://github.com/feathersjs/feathers/commit/65637ec))
-
-
-
-
+- Fix regression in transport commons ([#1551](https://github.com/feathersjs/feathers/issues/1551)) ([ed9e934](https://github.com/feathersjs/feathers/commit/ed9e934))
+- Omit standard protocol ports from the default hostname ([#1543](https://github.com/feathersjs/feathers/issues/1543)) ([ef16d29](https://github.com/feathersjs/feathers/commit/ef16d29))
+- Use long-timeout for JWT expiration timers ([#1552](https://github.com/feathersjs/feathers/issues/1552)) ([65637ec](https://github.com/feathersjs/feathers/commit/65637ec))
# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)
-
### Bug Fixes
-* 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))
-
-
-
-
+- 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))
# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)
-
### Bug Fixes
-* Fix auth publisher mistake ([08bad61](https://github.com/feathersjs/feathers/commit/08bad61))
-
-
-
-
+- Fix auth publisher mistake ([08bad61](https://github.com/feathersjs/feathers/commit/08bad61))
# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)
-
### Bug Fixes
-* Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))
-* Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))
-* Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))
-
+- Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))
+- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))
+- Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))
### Features
-* Let strategies handle the connection ([#1510](https://github.com/feathersjs/feathers/issues/1510)) ([4329feb](https://github.com/feathersjs/feathers/commit/4329feb))
-
-
-
-
+- Let strategies handle the connection ([#1510](https://github.com/feathersjs/feathers/issues/1510)) ([4329feb](https://github.com/feathersjs/feathers/commit/4329feb))
# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)
-
### Bug Fixes
-* @feathersjs/adapter-commons: `update` id is non-nullable ([#1468](https://github.com/feathersjs/feathers/issues/1468)) ([43ec802](https://github.com/feathersjs/feathers/commit/43ec802))
-* 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))
-* Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))
-* Do not error in authentication client on logout ([#1473](https://github.com/feathersjs/feathers/issues/1473)) ([8211b98](https://github.com/feathersjs/feathers/commit/8211b98))
-* Improve Params typing ([#1474](https://github.com/feathersjs/feathers/issues/1474)) ([54a3aa7](https://github.com/feathersjs/feathers/commit/54a3aa7))
-
-
-
-
+- @feathersjs/adapter-commons: `update` id is non-nullable ([#1468](https://github.com/feathersjs/feathers/issues/1468)) ([43ec802](https://github.com/feathersjs/feathers/commit/43ec802))
+- 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))
+- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))
+- Do not error in authentication client on logout ([#1473](https://github.com/feathersjs/feathers/issues/1473)) ([8211b98](https://github.com/feathersjs/feathers/commit/8211b98))
+- Improve Params typing ([#1474](https://github.com/feathersjs/feathers/issues/1474)) ([54a3aa7](https://github.com/feathersjs/feathers/commit/54a3aa7))
# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)
**Note:** Version bump only for package feathers
-
-
-
-
# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)
-
### Bug Fixes
-* Fix feathers-memory dependency that did not get updated ([9422b13](https://github.com/feathersjs/feathers/commit/9422b13))
-* 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))
-
+- Fix feathers-memory dependency that did not get updated ([9422b13](https://github.com/feathersjs/feathers/commit/9422b13))
+- 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))
### Features
-* @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))
-
-
-
-
+- @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))
# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)
-
### Bug Fixes
-* @feathersjs/adapter-commons: remove data from `remove` arguments ([#1426](https://github.com/feathersjs/feathers/issues/1426)) ([fd54ae9](https://github.com/feathersjs/feathers/commit/fd54ae9))
-* @feathersjs/express: allow middleware arrays ([#1421](https://github.com/feathersjs/feathers/issues/1421)) ([b605ab8](https://github.com/feathersjs/feathers/commit/b605ab8))
-* @feathersjs/express: replace `reduce` with `map` ([#1429](https://github.com/feathersjs/feathers/issues/1429)) ([44542e9](https://github.com/feathersjs/feathers/commit/44542e9))
-* Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))
-* Fix @feathersjs/feathers typings http import ([abbc07b](https://github.com/feathersjs/feathers/commit/abbc07b))
-* Fix OpenCollective link ([28888a1](https://github.com/feathersjs/feathers/commit/28888a1))
-* Improve transport-commons types ([#1396](https://github.com/feathersjs/feathers/issues/1396)) ([f9d8536](https://github.com/feathersjs/feathers/commit/f9d8536))
-* Updated typings for ServiceMethods ([#1409](https://github.com/feathersjs/feathers/issues/1409)) ([b5ee7e2](https://github.com/feathersjs/feathers/commit/b5ee7e2))
-
+- @feathersjs/adapter-commons: remove data from `remove` arguments ([#1426](https://github.com/feathersjs/feathers/issues/1426)) ([fd54ae9](https://github.com/feathersjs/feathers/commit/fd54ae9))
+- @feathersjs/express: allow middleware arrays ([#1421](https://github.com/feathersjs/feathers/issues/1421)) ([b605ab8](https://github.com/feathersjs/feathers/commit/b605ab8))
+- @feathersjs/express: replace `reduce` with `map` ([#1429](https://github.com/feathersjs/feathers/issues/1429)) ([44542e9](https://github.com/feathersjs/feathers/commit/44542e9))
+- Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))
+- Fix @feathersjs/feathers typings http import ([abbc07b](https://github.com/feathersjs/feathers/commit/abbc07b))
+- Fix OpenCollective link ([28888a1](https://github.com/feathersjs/feathers/commit/28888a1))
+- Improve transport-commons types ([#1396](https://github.com/feathersjs/feathers/issues/1396)) ([f9d8536](https://github.com/feathersjs/feathers/commit/f9d8536))
+- Updated typings for ServiceMethods ([#1409](https://github.com/feathersjs/feathers/issues/1409)) ([b5ee7e2](https://github.com/feathersjs/feathers/commit/b5ee7e2))
### Features
-* adapter-commons: add `allowsMulti(method)` to AdapterService ([#1431](https://github.com/feathersjs/feathers/issues/1431)) ([e688851](https://github.com/feathersjs/feathers/commit/e688851))
-* 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))
-
-
-
-
+- adapter-commons: add `allowsMulti(method)` to AdapterService ([#1431](https://github.com/feathersjs/feathers/issues/1431)) ([e688851](https://github.com/feathersjs/feathers/commit/e688851))
+- 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))
# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)
-
### Bug Fixes
-* 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))
-* Set authenticated: true after successful authentication ([#1367](https://github.com/feathersjs/feathers/issues/1367)) ([9918cff](https://github.com/feathersjs/feathers/commit/9918cff))
-* Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))
-* Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))
-
-
-
-
+- 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))
+- Set authenticated: true after successful authentication ([#1367](https://github.com/feathersjs/feathers/issues/1367)) ([9918cff](https://github.com/feathersjs/feathers/commit/9918cff))
+- Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))
+- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))
# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)
-
### Bug Fixes
-* Throw NotAuthenticated on token verification errors ([#1357](https://github.com/feathersjs/feathers/issues/1357)) ([e0120df](https://github.com/feathersjs/feathers/commit/e0120df))
-* **typescript:** finally should be optional ([#1350](https://github.com/feathersjs/feathers/issues/1350)) ([f439a9e](https://github.com/feathersjs/feathers/commit/f439a9e))
-* Add fallback for legacy socket authenticate event ([#1356](https://github.com/feathersjs/feathers/issues/1356)) ([61b1056](https://github.com/feathersjs/feathers/commit/61b1056))
-* Correctly read the oauth strategy config ([#1349](https://github.com/feathersjs/feathers/issues/1349)) ([9abf314](https://github.com/feathersjs/feathers/commit/9abf314))
-* Fix versioning tests. Closes [#1346](https://github.com/feathersjs/feathers/issues/1346) ([dd519f6](https://github.com/feathersjs/feathers/commit/dd519f6))
-* Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))
-
+- Throw NotAuthenticated on token verification errors ([#1357](https://github.com/feathersjs/feathers/issues/1357)) ([e0120df](https://github.com/feathersjs/feathers/commit/e0120df))
+- **typescript:** finally should be optional ([#1350](https://github.com/feathersjs/feathers/issues/1350)) ([f439a9e](https://github.com/feathersjs/feathers/commit/f439a9e))
+- Add fallback for legacy socket authenticate event ([#1356](https://github.com/feathersjs/feathers/issues/1356)) ([61b1056](https://github.com/feathersjs/feathers/commit/61b1056))
+- Correctly read the oauth strategy config ([#1349](https://github.com/feathersjs/feathers/issues/1349)) ([9abf314](https://github.com/feathersjs/feathers/commit/9abf314))
+- Fix versioning tests. Closes [#1346](https://github.com/feathersjs/feathers/issues/1346) ([dd519f6](https://github.com/feathersjs/feathers/commit/dd519f6))
+- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))
### Features
-* Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))
-
-
-
-
+- Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))
# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)
-
### Bug Fixes
-* Add registerPublisher alias for .publish ([#1302](https://github.com/feathersjs/feathers/issues/1302)) ([98fe8f8](https://github.com/feathersjs/feathers/commit/98fe8f8))
-* Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))
-* Bring back params.authenticated ([#1317](https://github.com/feathersjs/feathers/issues/1317)) ([a0ffd5e](https://github.com/feathersjs/feathers/commit/a0ffd5e))
-* 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))
-* Guard against null in client side logout function ([#1319](https://github.com/feathersjs/feathers/issues/1319)) ([fa7f057](https://github.com/feathersjs/feathers/commit/fa7f057))
-* Handle error oAuth redirect in authentication client ([#1307](https://github.com/feathersjs/feathers/issues/1307)) ([12d48ee](https://github.com/feathersjs/feathers/commit/12d48ee))
-* Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))
-* Improve oAuth option handling and usability ([#1335](https://github.com/feathersjs/feathers/issues/1335)) ([adb137d](https://github.com/feathersjs/feathers/commit/adb137d))
-* Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))
-* Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))
-* Update version number check ([53575c5](https://github.com/feathersjs/feathers/commit/53575c5))
-* Updated HooksObject typings ([#1300](https://github.com/feathersjs/feathers/issues/1300)) ([b28058c](https://github.com/feathersjs/feathers/commit/b28058c))
-
+- Add registerPublisher alias for .publish ([#1302](https://github.com/feathersjs/feathers/issues/1302)) ([98fe8f8](https://github.com/feathersjs/feathers/commit/98fe8f8))
+- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))
+- Bring back params.authenticated ([#1317](https://github.com/feathersjs/feathers/issues/1317)) ([a0ffd5e](https://github.com/feathersjs/feathers/commit/a0ffd5e))
+- 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))
+- Guard against null in client side logout function ([#1319](https://github.com/feathersjs/feathers/issues/1319)) ([fa7f057](https://github.com/feathersjs/feathers/commit/fa7f057))
+- Handle error oAuth redirect in authentication client ([#1307](https://github.com/feathersjs/feathers/issues/1307)) ([12d48ee](https://github.com/feathersjs/feathers/commit/12d48ee))
+- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))
+- Improve oAuth option handling and usability ([#1335](https://github.com/feathersjs/feathers/issues/1335)) ([adb137d](https://github.com/feathersjs/feathers/commit/adb137d))
+- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))
+- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))
+- Update version number check ([53575c5](https://github.com/feathersjs/feathers/commit/53575c5))
+- Updated HooksObject typings ([#1300](https://github.com/feathersjs/feathers/issues/1300)) ([b28058c](https://github.com/feathersjs/feathers/commit/b28058c))
### Features
-* Add params.headers to all transports when available ([#1303](https://github.com/feathersjs/feathers/issues/1303)) ([ebce79b](https://github.com/feathersjs/feathers/commit/ebce79b))
-* Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))
-* express use service.methods ([#945](https://github.com/feathersjs/feathers/issues/945)) ([3f0b1c3](https://github.com/feathersjs/feathers/commit/3f0b1c3))
-
-
-
-
+- Add params.headers to all transports when available ([#1303](https://github.com/feathersjs/feathers/issues/1303)) ([ebce79b](https://github.com/feathersjs/feathers/commit/ebce79b))
+- Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))
+- express use service.methods ([#945](https://github.com/feathersjs/feathers/issues/945)) ([3f0b1c3](https://github.com/feathersjs/feathers/commit/3f0b1c3))
# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)
-
### Bug Fixes
-* 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))
-* 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))
-* 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))
-* Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))
-* Catch connection initialization errors ([#1043](https://github.com/feathersjs/feathers/issues/1043)) ([4f9acd6](https://github.com/feathersjs/feathers/commit/4f9acd6))
-* 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))
-* Do not inherit app object from Object prototype ([#1153](https://github.com/feathersjs/feathers/issues/1153)) ([ed8c2e4](https://github.com/feathersjs/feathers/commit/ed8c2e4))
-* Fix AdapterService multi option when set to true ([#1134](https://github.com/feathersjs/feathers/issues/1134)) ([40402fc](https://github.com/feathersjs/feathers/commit/40402fc))
-* Improve JWT authentication option handling ([#1261](https://github.com/feathersjs/feathers/issues/1261)) ([31b956b](https://github.com/feathersjs/feathers/commit/31b956b))
-* make codeclimate conform to rule of three ([#1076](https://github.com/feathersjs/feathers/issues/1076)) ([0a2ce87](https://github.com/feathersjs/feathers/commit/0a2ce87))
-* Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))
-* 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))
-* 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))
-* Only merge authenticated property on update ([8a564f7](https://github.com/feathersjs/feathers/commit/8a564f7))
-* reduce authentication connection hook complexity and remove unnecessary checks ([fa94b2f](https://github.com/feathersjs/feathers/commit/fa94b2f))
-* support a secretProvider ([#1063](https://github.com/feathersjs/feathers/issues/1063)) ([9da26ad](https://github.com/feathersjs/feathers/commit/9da26ad))
-* 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)
-* 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))
-* Update 401.html ([#983](https://github.com/feathersjs/feathers/issues/983)) ([cec6bae](https://github.com/feathersjs/feathers/commit/cec6bae))
-* Update 404.html ([#984](https://github.com/feathersjs/feathers/issues/984)) ([72132d1](https://github.com/feathersjs/feathers/commit/72132d1))
-* Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))
-* Update adapter common tests to check for falsy ([#1140](https://github.com/feathersjs/feathers/issues/1140)) ([2856722](https://github.com/feathersjs/feathers/commit/2856722))
-* 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))
-* Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))
-* **adapter-commons:** Keep Symbols when filtering a query ([#1141](https://github.com/feathersjs/feathers/issues/1141)) ([c9f55d8](https://github.com/feathersjs/feathers/commit/c9f55d8))
-* **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))
-* **chore:** Add .npmignore to adapter-commons ([8e129d8](https://github.com/feathersjs/feathers/commit/8e129d8))
-* **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))
-* **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))
-* **compile-task:** on windows machine ([#60](https://github.com/feathersjs/feathers/issues/60)) ([617e0a4](https://github.com/feathersjs/feathers/commit/617e0a4))
-* **docs/new-features:** syntax highlighting ([#347](https://github.com/feathersjs/feathers/issues/347)) ([4ab7c95](https://github.com/feathersjs/feathers/commit/4ab7c95))
-* **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))
-* **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))
-* **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))
-* **package:** update config to version 3.0.0 ([#1100](https://github.com/feathersjs/feathers/issues/1100)) ([c9f4b42](https://github.com/feathersjs/feathers/commit/c9f4b42))
-* use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97))
-* **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))
-* **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))
-* **package:** update debug to version 3.0.0 ([#2](https://github.com/feathersjs/feathers/issues/2)) ([7e19603](https://github.com/feathersjs/feathers/commit/7e19603))
-* **package:** update debug to version 3.0.0 ([#22](https://github.com/feathersjs/feathers/issues/22)) ([0b62606](https://github.com/feathersjs/feathers/commit/0b62606))
-* **package:** update debug to version 3.0.0 ([#30](https://github.com/feathersjs/feathers/issues/30)) ([baf7a00](https://github.com/feathersjs/feathers/commit/baf7a00))
-* **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([902ddf5](https://github.com/feathersjs/feathers/commit/902ddf5))
-* **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([f23d617](https://github.com/feathersjs/feathers/commit/f23d617))
-* **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([2391434](https://github.com/feathersjs/feathers/commit/2391434))
-* **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([9b9bde5](https://github.com/feathersjs/feathers/commit/9b9bde5))
-* **package:** update debug to version 3.0.0 ([#555](https://github.com/feathersjs/feathers/issues/555)) ([f788804](https://github.com/feathersjs/feathers/commit/f788804))
-* **package:** update debug to version 3.0.0 ([#59](https://github.com/feathersjs/feathers/issues/59)) ([fedcf06](https://github.com/feathersjs/feathers/commit/fedcf06))
-* **package:** update debug to version 3.0.0 ([#61](https://github.com/feathersjs/feathers/issues/61)) ([6f5009c](https://github.com/feathersjs/feathers/commit/6f5009c))
-* **package:** update debug to version 3.0.0 ([#83](https://github.com/feathersjs/feathers/issues/83)) ([49f1de9](https://github.com/feathersjs/feathers/commit/49f1de9))
-* **package:** update debug to version 3.0.0 ([#86](https://github.com/feathersjs/feathers/issues/86)) ([fd1bb6b](https://github.com/feathersjs/feathers/commit/fd1bb6b))
-* **package:** update debug to version 3.0.1 ([#46](https://github.com/feathersjs/feathers/issues/46)) ([f8ada69](https://github.com/feathersjs/feathers/commit/f8ada69))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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)
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **package:** update jsonwebtoken to version 8.0.0 ([#567](https://github.com/feathersjs/feathers/issues/567)) ([6811626](https://github.com/feathersjs/feathers/commit/6811626))
-* **package:** update ms to version 2.0.0 ([#509](https://github.com/feathersjs/feathers/issues/509)) ([7e4b0b6](https://github.com/feathersjs/feathers/commit/7e4b0b6))
-* **package:** update passport to version 0.4.0 ([#558](https://github.com/feathersjs/feathers/issues/558)) ([dcb14a5](https://github.com/feathersjs/feathers/commit/dcb14a5))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-* **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))
-
+- 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))
+- 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))
+- 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))
+- Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))
+- Catch connection initialization errors ([#1043](https://github.com/feathersjs/feathers/issues/1043)) ([4f9acd6](https://github.com/feathersjs/feathers/commit/4f9acd6))
+- 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))
+- Do not inherit app object from Object prototype ([#1153](https://github.com/feathersjs/feathers/issues/1153)) ([ed8c2e4](https://github.com/feathersjs/feathers/commit/ed8c2e4))
+- Fix AdapterService multi option when set to true ([#1134](https://github.com/feathersjs/feathers/issues/1134)) ([40402fc](https://github.com/feathersjs/feathers/commit/40402fc))
+- Improve JWT authentication option handling ([#1261](https://github.com/feathersjs/feathers/issues/1261)) ([31b956b](https://github.com/feathersjs/feathers/commit/31b956b))
+- make codeclimate conform to rule of three ([#1076](https://github.com/feathersjs/feathers/issues/1076)) ([0a2ce87](https://github.com/feathersjs/feathers/commit/0a2ce87))
+- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))
+- 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))
+- 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))
+- Only merge authenticated property on update ([8a564f7](https://github.com/feathersjs/feathers/commit/8a564f7))
+- reduce authentication connection hook complexity and remove unnecessary checks ([fa94b2f](https://github.com/feathersjs/feathers/commit/fa94b2f))
+- support a secretProvider ([#1063](https://github.com/feathersjs/feathers/issues/1063)) ([9da26ad](https://github.com/feathersjs/feathers/commit/9da26ad))
+- 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)
+- 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))
+- Update 401.html ([#983](https://github.com/feathersjs/feathers/issues/983)) ([cec6bae](https://github.com/feathersjs/feathers/commit/cec6bae))
+- Update 404.html ([#984](https://github.com/feathersjs/feathers/issues/984)) ([72132d1](https://github.com/feathersjs/feathers/commit/72132d1))
+- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))
+- Update adapter common tests to check for falsy ([#1140](https://github.com/feathersjs/feathers/issues/1140)) ([2856722](https://github.com/feathersjs/feathers/commit/2856722))
+- 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))
+- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))
+- **adapter-commons:** Keep Symbols when filtering a query ([#1141](https://github.com/feathersjs/feathers/issues/1141)) ([c9f55d8](https://github.com/feathersjs/feathers/commit/c9f55d8))
+- **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))
+- **chore:** Add .npmignore to adapter-commons ([8e129d8](https://github.com/feathersjs/feathers/commit/8e129d8))
+- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))
+- **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))
+- **compile-task:** on windows machine ([#60](https://github.com/feathersjs/feathers/issues/60)) ([617e0a4](https://github.com/feathersjs/feathers/commit/617e0a4))
+- **docs/new-features:** syntax highlighting ([#347](https://github.com/feathersjs/feathers/issues/347)) ([4ab7c95](https://github.com/feathersjs/feathers/commit/4ab7c95))
+- **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))
+- **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))
+- **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))
+- **package:** update config to version 3.0.0 ([#1100](https://github.com/feathersjs/feathers/issues/1100)) ([c9f4b42](https://github.com/feathersjs/feathers/commit/c9f4b42))
+- use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97))
+- **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))
+- **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))
+- **package:** update debug to version 3.0.0 ([#2](https://github.com/feathersjs/feathers/issues/2)) ([7e19603](https://github.com/feathersjs/feathers/commit/7e19603))
+- **package:** update debug to version 3.0.0 ([#22](https://github.com/feathersjs/feathers/issues/22)) ([0b62606](https://github.com/feathersjs/feathers/commit/0b62606))
+- **package:** update debug to version 3.0.0 ([#30](https://github.com/feathersjs/feathers/issues/30)) ([baf7a00](https://github.com/feathersjs/feathers/commit/baf7a00))
+- **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([902ddf5](https://github.com/feathersjs/feathers/commit/902ddf5))
+- **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([f23d617](https://github.com/feathersjs/feathers/commit/f23d617))
+- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([2391434](https://github.com/feathersjs/feathers/commit/2391434))
+- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([9b9bde5](https://github.com/feathersjs/feathers/commit/9b9bde5))
+- **package:** update debug to version 3.0.0 ([#555](https://github.com/feathersjs/feathers/issues/555)) ([f788804](https://github.com/feathersjs/feathers/commit/f788804))
+- **package:** update debug to version 3.0.0 ([#59](https://github.com/feathersjs/feathers/issues/59)) ([fedcf06](https://github.com/feathersjs/feathers/commit/fedcf06))
+- **package:** update debug to version 3.0.0 ([#61](https://github.com/feathersjs/feathers/issues/61)) ([6f5009c](https://github.com/feathersjs/feathers/commit/6f5009c))
+- **package:** update debug to version 3.0.0 ([#83](https://github.com/feathersjs/feathers/issues/83)) ([49f1de9](https://github.com/feathersjs/feathers/commit/49f1de9))
+- **package:** update debug to version 3.0.0 ([#86](https://github.com/feathersjs/feathers/issues/86)) ([fd1bb6b](https://github.com/feathersjs/feathers/commit/fd1bb6b))
+- **package:** update debug to version 3.0.1 ([#46](https://github.com/feathersjs/feathers/issues/46)) ([f8ada69](https://github.com/feathersjs/feathers/commit/f8ada69))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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)
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **package:** update jsonwebtoken to version 8.0.0 ([#567](https://github.com/feathersjs/feathers/issues/567)) ([6811626](https://github.com/feathersjs/feathers/commit/6811626))
+- **package:** update ms to version 2.0.0 ([#509](https://github.com/feathersjs/feathers/issues/509)) ([7e4b0b6](https://github.com/feathersjs/feathers/commit/7e4b0b6))
+- **package:** update passport to version 0.4.0 ([#558](https://github.com/feathersjs/feathers/issues/558)) ([dcb14a5](https://github.com/feathersjs/feathers/commit/dcb14a5))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
+- **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))
### chore
-* **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))
-* drop support for Node.js 0.10 ([#48](https://github.com/feathersjs/feathers/issues/48)) ([3f7555a](https://github.com/feathersjs/feathers/commit/3f7555a))
-
+- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))
+- drop support for Node.js 0.10 ([#48](https://github.com/feathersjs/feathers/issues/48)) ([3f7555a](https://github.com/feathersjs/feathers/commit/3f7555a))
### Features
-* @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))
-* @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))
-* Add authentication through oAuth redirect to authentication client ([#1301](https://github.com/feathersjs/feathers/issues/1301)) ([35d8043](https://github.com/feathersjs/feathers/commit/35d8043))
-* 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))
-* Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))
-* Added generators for feathers-objection & feathers-cassandra ([#1010](https://github.com/feathersjs/feathers/issues/1010)) ([c8b27d0](https://github.com/feathersjs/feathers/commit/c8b27d0))
-* Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))
-* Allow to skip sending service events ([#1270](https://github.com/feathersjs/feathers/issues/1270)) ([b487bbd](https://github.com/feathersjs/feathers/commit/b487bbd))
-* Authentication v3 client ([#1240](https://github.com/feathersjs/feathers/issues/1240)) ([65b43bd](https://github.com/feathersjs/feathers/commit/65b43bd))
-* Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))
-* Authentication v3 Express integration ([#1218](https://github.com/feathersjs/feathers/issues/1218)) ([82bcfbe](https://github.com/feathersjs/feathers/commit/82bcfbe))
-* Authentication v3 local authentication ([#1211](https://github.com/feathersjs/feathers/issues/1211)) ([0fa5f7c](https://github.com/feathersjs/feathers/commit/0fa5f7c))
-* Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))
-* Make custom query for oAuth authentication ([#1124](https://github.com/feathersjs/feathers/issues/1124)) ([5d43e3c](https://github.com/feathersjs/feathers/commit/5d43e3c))
-* Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))
-* Support params symbol to skip authenticate hook ([#1296](https://github.com/feathersjs/feathers/issues/1296)) ([d16cf4d](https://github.com/feathersjs/feathers/commit/d16cf4d))
-
+- @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))
+- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))
+- Add authentication through oAuth redirect to authentication client ([#1301](https://github.com/feathersjs/feathers/issues/1301)) ([35d8043](https://github.com/feathersjs/feathers/commit/35d8043))
+- 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))
+- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))
+- Added generators for feathers-objection & feathers-cassandra ([#1010](https://github.com/feathersjs/feathers/issues/1010)) ([c8b27d0](https://github.com/feathersjs/feathers/commit/c8b27d0))
+- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))
+- Allow to skip sending service events ([#1270](https://github.com/feathersjs/feathers/issues/1270)) ([b487bbd](https://github.com/feathersjs/feathers/commit/b487bbd))
+- Authentication v3 client ([#1240](https://github.com/feathersjs/feathers/issues/1240)) ([65b43bd](https://github.com/feathersjs/feathers/commit/65b43bd))
+- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))
+- Authentication v3 Express integration ([#1218](https://github.com/feathersjs/feathers/issues/1218)) ([82bcfbe](https://github.com/feathersjs/feathers/commit/82bcfbe))
+- Authentication v3 local authentication ([#1211](https://github.com/feathersjs/feathers/issues/1211)) ([0fa5f7c](https://github.com/feathersjs/feathers/commit/0fa5f7c))
+- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))
+- Make custom query for oAuth authentication ([#1124](https://github.com/feathersjs/feathers/issues/1124)) ([5d43e3c](https://github.com/feathersjs/feathers/commit/5d43e3c))
+- Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))
+- Support params symbol to skip authenticate hook ([#1296](https://github.com/feathersjs/feathers/issues/1296)) ([d16cf4d](https://github.com/feathersjs/feathers/commit/d16cf4d))
### BREAKING CHANGES
-* Rewrite for authentication v3
-* Update authentication strategies for @feathersjs/authentication v3
-* **package:** Removes adapter tests from @feathersjs/adapter-commons
-* Move database adapter utilities from @feathersjs/commons into its own module
-* This module no longer supports Node.js 0.10
+- Rewrite for authentication v3
+- Update authentication strategies for @feathersjs/authentication v3
+- **package:** Removes adapter tests from @feathersjs/adapter-commons
+- Move database adapter utilities from @feathersjs/commons into its own module
+- This module no longer supports Node.js 0.10
diff --git a/LICENSE b/LICENSE
index 3f395cc665..59604f46f3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2021 Feathers
+Copyright (c) 2022 Feathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/packages/feathers/readme.md b/README.md
similarity index 91%
rename from packages/feathers/readme.md
rename to README.md
index 46eba676a6..01be1db801 100644
--- a/packages/feathers/readme.md
+++ b/README.md
@@ -6,6 +6,7 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/maintainability)](https://codeclimate.com/github/feathersjs/feathers/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/test_coverage)](https://codeclimate.com/github/feathersjs/feathers/test_coverage)
[![Download Status](https://img.shields.io/npm/dm/@feathersjs/feathers.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)
+[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)
Feathers is a lightweight web-framework for creating real-time applications and REST APIs using JavaScript or TypeScript.
@@ -31,6 +32,6 @@ The [Feathers docs](http://docs.feathersjs.com) are loaded with awesome stuff an
## License
-Copyright (c) 2021 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)
+Copyright (c) 2022 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)
Licensed under the [MIT license](LICENSE).
diff --git a/_templates/package/new/index.test.ts.t b/_templates/package/new/index.test.ts.t
deleted file mode 100644
index 053c5be400..0000000000
--- a/_templates/package/new/index.test.ts.t
+++ /dev/null
@@ -1,12 +0,0 @@
----
-to: packages/<%= name %>/test/index.test.ts
----
-
-import assert from 'assert';
-import { hello } from '../src';
-
-describe('@feathersjs/<%= name %>', () => {
- it('initializes', async () => {
- assert.strictEqual(hello(), 'Hello');
- });
-});
diff --git a/_templates/package/new/index.ts.t b/_templates/package/new/index.ts.t
deleted file mode 100644
index b0120efce8..0000000000
--- a/_templates/package/new/index.ts.t
+++ /dev/null
@@ -1,7 +0,0 @@
----
-to: packages/<%= name %>/src/index.ts
----
-
-export function hello () {
- return 'Hello';
-}
diff --git a/deno/LICENSE b/deno/LICENSE
index 3f395cc665..59604f46f3 100644
--- a/deno/LICENSE
+++ b/deno/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2021 Feathers
+Copyright (c) 2022 Feathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/deno/readme.md b/deno/README.md
similarity index 94%
rename from deno/readme.md
rename to deno/README.md
index 6b8ef62fc5..63d9d4ecd4 100644
--- a/deno/readme.md
+++ b/deno/README.md
@@ -10,7 +10,7 @@ This folder contains the Deno build of Feathers.
// app.ts
import { feathers } from 'https://deno.land/x/feathers@v5.0.0-pre.3/mod.ts';
-type Message {
+type Message = {
message: string;
}
@@ -20,7 +20,7 @@ class MyService {
}
}
-type ServiceTypes {
+type ServiceTypes = {
myservice: MyService
}
diff --git a/lerna.json b/lerna.json
index 3908b2f63f..a6b6a52736 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,18 +1,13 @@
{
"ci": false,
- "packages": [
- "packages/*"
- ],
- "version": "5.0.0-pre.16",
+ "packages": ["packages/*"],
+ "version": "5.0.0-pre.31",
"command": {
"bootstrap": {
"hoist": true
},
"publish": {
- "allowBranch": [
- "crow",
- "dove"
- ],
+ "allowBranch": ["crow", "dove"],
"message": "chore(release): publish %s",
"conventionalCommits": true,
"createRelease": "github"
diff --git a/main/adapter-commons/LICENSE b/main/adapter-commons/LICENSE
index 3f395cc665..59604f46f3 100644
--- a/main/adapter-commons/LICENSE
+++ b/main/adapter-commons/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2021 Feathers
+Copyright (c) 2022 Feathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/main/adapter-commons/mod.ts b/main/adapter-commons/mod.ts
new file mode 100644
index 0000000000..3b3419b271
--- /dev/null
+++ b/main/adapter-commons/mod.ts
@@ -0,0 +1 @@
+export * from "./src/index.ts";
diff --git a/main/adapter-commons/src/declarations.ts b/main/adapter-commons/src/declarations.ts
new file mode 100644
index 0000000000..3d9543f40f
--- /dev/null
+++ b/main/adapter-commons/src/declarations.ts
@@ -0,0 +1,166 @@
+import {
+ Query,
+ Params,
+ Paginated,
+ Id,
+ NullableId,
+} from "../../feathers/mod.ts";
+
+export type FilterQueryOptions = {
+ filters?: FilterSettings;
+ operators?: string[];
+ paginate?: PaginationParams;
+};
+
+export type QueryFilter = (value: any, options: FilterQueryOptions) => any;
+
+export type FilterSettings = {
+ [key: string]: QueryFilter | true;
+};
+
+export interface PaginationOptions {
+ default?: number;
+ max?: number;
+}
+
+export type PaginationParams = false | PaginationOptions;
+
+export interface AdapterServiceOptions {
+ /**
+ * Whether to allow multiple updates for everything (`true`) or specific methods (e.g. `['create', 'remove']`)
+ */
+ multi?: boolean | string[];
+ /**
+ * The name of the id property
+ */
+ id?: string;
+ /**
+ * Pagination settings for this service
+ */
+ paginate?: PaginationParams;
+ /**
+ * A list of additional property query operators to allow in a query
+ */
+ operators?: string[];
+ /**
+ * 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 }`
+ */
+ filters?: FilterSettings;
+ /**
+ * @deprecated Use service `events` option when registering the service with `app.use`.
+ */
+ events?: string[];
+ /**
+ * @deprecated renamed to `operators`.
+ */
+ whitelist?: string[];
+}
+
+export interface AdapterQuery extends Query {
+ $limit?: number;
+ $skip?: number;
+ $select?: string[];
+ $sort?: { [key: string]: 1 | -1 };
+}
+/**
+ * Additional `params` that can be passed to an adapter service method call.
+ */
+export interface AdapterParams<
+ Q = AdapterQuery,
+ A extends Partial = Partial
+> extends Params {
+ adapter?: A;
+ paginate?: PaginationParams;
+}
+
+/**
+ * Hook-less (internal) service methods. Directly call database adapter service methods
+ * without running any service-level hooks or sanitization. This can be useful if you need the raw data
+ * from the service and don't want to trigger any of its hooks.
+ *
+ * Important: These methods are only available internally on the server, not on the client
+ * side and only for the Feathers database adapters.
+ *
+ * These methods do not trigger events.
+ *
+ * @see {@link https://docs.feathersjs.com/guides/migrating.html#hook-less-service-methods}
+ */
+export interface InternalServiceMethods<
+ T = any,
+ D = Partial,
+ P extends AdapterParams = AdapterParams
+> {
+ /**
+ * Retrieve all resources from this service.
+ * Does not sanitize the query and should only be used on the server.
+ *
+ * @param _params - Service call parameters {@link Params}
+ */
+ $find(_params?: P & { paginate?: PaginationOptions }): Promise>;
+ $find(_params?: P & { paginate: false }): Promise;
+ $find(params?: P): Promise>;
+
+ /**
+ * Retrieve a single resource matching the given ID, skipping any service-level hooks.
+ * Does not sanitize the query and should only be used on the server.
+ *
+ * @param id - ID of the resource to locate
+ * @param params - Service call parameters {@link Params}
+ * @see {@link HookLessServiceMethods}
+ * @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}
+ */
+ $get(id: Id, params?: P): Promise;
+
+ /**
+ * Create a new resource for this service, skipping any service-level hooks.
+ * Does not sanitize data or checks if multiple updates are allowed and should only be used on the server.
+ *
+ * @param data - Data to insert into this service.
+ * @param params - Service call parameters {@link Params}
+ * @see {@link HookLessServiceMethods}
+ * @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}
+ */
+ $create(data: Partial, params?: P): Promise;
+ $create(data: Partial[], params?: P): Promise;
+ $create(data: Partial | Partial[], params?: P): Promise;
+
+ /**
+ * Completely replace the resource identified by id, skipping any service-level hooks.
+ * Does not sanitize data or query and should only be used on the server.
+ *
+ * @param id - ID of the resource to be updated
+ * @param data - Data to be put in place of the current resource.
+ * @param params - Service call parameters {@link Params}
+ * @see {@link HookLessServiceMethods}
+ * @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}
+ */
+ $update(id: Id, data: D, params?: P): Promise;
+
+ /**
+ * Merge any resources matching the given ID with the given data, skipping any service-level hooks.
+ * Does not sanitize the data or query and should only be used on the server.
+ *
+ * @param id - ID of the resource to be patched
+ * @param data - Data to merge with the current resource.
+ * @param params - Service call parameters {@link Params}
+ * @see {@link HookLessServiceMethods}
+ * @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}
+ */
+ $patch(id: null, data: Partial, params?: P): Promise;
+ $patch(id: Id, data: Partial, params?: P): Promise;
+ $patch(id: NullableId, data: Partial, params?: P): Promise;
+
+ /**
+ * Remove resources matching the given ID from the this service, skipping any service-level hooks.
+ * Does not sanitize query and should only be used on the server.
+ *
+ * @param id - ID of the resource to be removed
+ * @param params - Service call parameters {@link Params}
+ * @see {@link HookLessServiceMethods}
+ * @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}
+ */
+ $remove(id: null, params?: P): Promise;
+ $remove(id: Id, params?: P): Promise;
+ $remove(id: NullableId, params?: P): Promise;
+}
diff --git a/main/adapter-commons/src/filter-query.ts b/main/adapter-commons/src/filter-query.ts
deleted file mode 100644
index 76d1067159..0000000000
--- a/main/adapter-commons/src/filter-query.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { _ } from '../../commons/src/index.ts';
-import { BadRequest } from '../../errors/src/index.ts';
-
-function parse (number: any) {
- if (typeof number !== 'undefined') {
- return Math.abs(parseInt(number, 10));
- }
-
- return undefined;
-}
-
-// Returns the pagination limit and will take into account the
-// default and max pagination settings
-function getLimit (limit: any, paginate: any) {
- if (paginate && (paginate.default || paginate.max)) {
- const base = paginate.default || 0;
- const lower = typeof limit === 'number' && !isNaN(limit) ? limit : base;
- const upper = typeof paginate.max === 'number' ? paginate.max : Number.MAX_VALUE;
-
- return Math.min(lower, upper);
- }
-
- return limit;
-}
-
-// Makes sure that $sort order is always converted to an actual number
-function convertSort (sort: any) {
- if (typeof sort !== 'object' || Array.isArray(sort)) {
- return sort;
- }
-
- return Object.keys(sort).reduce((result, key) => {
- result[key] = typeof sort[key] === 'object'
- ? sort[key] : parseInt(sort[key], 10);
-
- return result;
- }, {} as { [key: string]: number });
-}
-
-function cleanQuery (query: any, operators: any, filters: any): any {
- if (Array.isArray(query)) {
- return query.map(value => cleanQuery(value, operators, filters));
- } else if (_.isObject(query) && query.constructor === {}.constructor) {
- const result: { [key: string]: any } = {};
-
- _.each(query, (value, key) => {
- if (key[0] === '$') {
- if (filters[key] !== undefined) {
- return;
- }
-
- if (!operators.includes(key)) {
- throw new BadRequest(`Invalid query parameter ${key}`, query);
- }
- }
-
- result[key] = cleanQuery(value, operators, filters);
- });
-
- Object.getOwnPropertySymbols(query).forEach(symbol => {
- // @ts-ignore
- result[symbol] = query[symbol];
- });
-
- return result;
- }
-
- return query;
-}
-
-function assignFilters (object: any, query: any, filters: any, options: any) {
- if (Array.isArray(filters)) {
- _.each(filters, (key) => {
- if (query[key] !== undefined) {
- object[key] = query[key];
- }
- });
- } else {
- _.each(filters, (converter, key) => {
- const converted = converter(query[key], options);
-
- if (converted !== undefined) {
- object[key] = converted;
- }
- });
- }
-
- return object;
-}
-
-export const FILTERS = {
- $sort: (value: any) => convertSort(value),
- $limit: (value: any, options: any) => getLimit(parse(value), options.paginate),
- $skip: (value: any) => parse(value),
- $select: (value: any) => value
-};
-
-export const OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or'];
-
-// Converts Feathers special query parameters and pagination settings
-// and returns them separately a `filters` and the rest of the query
-// as `query`
-export function filterQuery (query: any, options: any = {}) {
- const {
- filters: additionalFilters = {},
- operators: additionalOperators = []
- } = options;
- const result: { [key: string]: any } = {};
-
- result.filters = assignFilters({}, query, FILTERS, options);
- result.filters = assignFilters(result.filters, query, additionalFilters, options);
-
- result.query = cleanQuery(query, OPERATORS.concat(additionalOperators), result.filters);
-
- return result;
-}
diff --git a/main/adapter-commons/src/index.ts b/main/adapter-commons/src/index.ts
index 1fae5a0ba3..81a47945f7 100644
--- a/main/adapter-commons/src/index.ts
+++ b/main/adapter-commons/src/index.ts
@@ -1,27 +1,23 @@
-import { _ } from '../../commons/src/index.ts';
+import { _ } from "../../commons/mod.ts";
+import { Params } from "../../feathers/mod.ts";
-export { AdapterService } from './service.ts';
-export type { InternalServiceMethods, ServiceOptions, AdapterParams } from './service.ts';
-export { filterQuery, FILTERS, OPERATORS } from './filter-query.ts';
-export * from './sort.ts';
+export * from "./declarations.ts";
+export * from "./service.ts";
+export { filterQuery, FILTERS, OPERATORS } from "./query.ts";
+export * from "./sort.ts";
// Return a function that filters a result object or array
// and picks only the fields passed as `params.query.$select`
// and additional `otherFields`
-export function select (params: any, ...otherFields: any[]) {
- const fields = params && params.query && params.query.$select;
+export function select(params: Params, ...otherFields: string[]) {
+ const queryFields: string[] | undefined = params?.query?.$select;
- if (Array.isArray(fields) && otherFields.length) {
- fields.push(...otherFields);
+ if (!queryFields) {
+ return (result: any) => result;
}
- const convert = (result: any) => {
- if (!Array.isArray(fields)) {
- return result;
- }
-
- return _.pick(result, ...fields);
- };
+ const resultFields = queryFields.concat(otherFields);
+ const convert = (result: any) => _.pick(result, ...resultFields);
return (result: any) => {
if (Array.isArray(result)) {
diff --git a/main/adapter-commons/src/query.ts b/main/adapter-commons/src/query.ts
new file mode 100644
index 0000000000..1a1df8e31a
--- /dev/null
+++ b/main/adapter-commons/src/query.ts
@@ -0,0 +1,156 @@
+import { _ } from "../../commons/mod.ts";
+import { BadRequest } from "../../errors/mod.ts";
+import { Query } from "../../feathers/mod.ts";
+import { FilterQueryOptions, FilterSettings } from "./declarations.ts";
+
+const parse = (value: any) =>
+ typeof value !== "undefined" ? parseInt(value, 10) : value;
+
+const isPlainObject = (value: any) =>
+ _.isObject(value) && value.constructor === {}.constructor;
+
+const validateQueryProperty = (query: any, operators: string[] = []): Query => {
+ if (!isPlainObject(query)) {
+ return query;
+ }
+
+ for (const key of Object.keys(query)) {
+ if (key.startsWith("$") && !operators.includes(key)) {
+ throw new BadRequest(`Invalid query parameter ${key}`, query);
+ }
+
+ const value = query[key];
+
+ if (isPlainObject(value)) {
+ query[key] = validateQueryProperty(value, operators);
+ }
+ }
+
+ return {
+ ...query,
+ };
+};
+
+const getFilters = (query: Query, settings: FilterQueryOptions) => {
+ const filterNames = Object.keys(settings.filters as object);
+
+ return filterNames.reduce((current, key) => {
+ const queryValue = query[key];
+ const filter = settings.filters?.[key];
+
+ if (filter) {
+ const value =
+ typeof filter === "function"
+ ? filter(queryValue, settings)
+ : queryValue;
+
+ if (value !== undefined) {
+ current[key] = value;
+ }
+ }
+
+ return current;
+ }, {} as { [key: string]: any });
+};
+
+const getQuery = (query: Query, settings: FilterQueryOptions) => {
+ const keys = Object.keys(query).concat(
+ Object.getOwnPropertySymbols(query) as any as string[]
+ );
+
+ return keys.reduce((result, key) => {
+ if (typeof key === "string" && key.startsWith("$")) {
+ if (settings.filters?.[key] === undefined) {
+ throw new BadRequest(`Invalid filter value ${key}`);
+ }
+ } else {
+ result[key] = validateQueryProperty(query[key], settings.operators);
+ }
+
+ return result;
+ }, {} as Query);
+};
+
+export const OPERATORS = [
+ "$in",
+ "$nin",
+ "$lt",
+ "$lte",
+ "$gt",
+ "$gte",
+ "$ne",
+ "$or",
+];
+
+export const FILTERS: FilterSettings = {
+ $skip: (value: any) => parse(value),
+ $sort: (sort: any): { [key: string]: number } => {
+ if (typeof sort !== "object" || Array.isArray(sort)) {
+ return sort;
+ }
+
+ return Object.keys(sort).reduce((result, key) => {
+ result[key] =
+ typeof sort[key] === "object" ? sort[key] : parse(sort[key]);
+
+ return result;
+ }, {} as { [key: string]: number });
+ },
+ $limit: (_limit: any, { paginate }: FilterQueryOptions) => {
+ const limit = parse(_limit);
+
+ if (paginate && (paginate.default || paginate.max)) {
+ const base = paginate.default || 0;
+ const lower =
+ typeof limit === "number" && !isNaN(limit) && limit >= 0 ? limit : base;
+ const upper =
+ typeof paginate.max === "number" ? paginate.max : Number.MAX_VALUE;
+
+ return Math.min(lower, upper);
+ }
+
+ return limit;
+ },
+ $select: (select: any) => {
+ if (Array.isArray(select)) {
+ return select.map((current) => `${current}`);
+ }
+
+ return select;
+ },
+ $or: (or: any, { operators }: FilterQueryOptions) => {
+ if (Array.isArray(or)) {
+ return or.map((current) => validateQueryProperty(current, operators));
+ }
+
+ return or;
+ },
+};
+
+/**
+ * Converts Feathers special query parameters and pagination settings
+ * and returns them separately as `filters` and the rest of the query
+ * as `query`. `options` also gets passed the pagination settings and
+ * a list of additional `operators` to allow when querying properties.
+ *
+ * @param query The initial query
+ * @param options Options for filtering the query
+ * @returns An object with `query` which contains the query without `filters`
+ * and `filters` which contains the converted values for each filter.
+ */
+export function filterQuery(_query: Query, options: FilterQueryOptions = {}) {
+ const query = _query || {};
+ const settings = {
+ ...options,
+ filters: {
+ ...FILTERS,
+ ...options.filters,
+ },
+ operators: OPERATORS.concat(options.operators || []),
+ };
+
+ return {
+ filters: getFilters(query, settings),
+ query: getQuery(query, settings),
+ };
+}
diff --git a/main/adapter-commons/src/service.ts b/main/adapter-commons/src/service.ts
index 53dd94e73d..cfece51427 100644
--- a/main/adapter-commons/src/service.ts
+++ b/main/adapter-commons/src/service.ts
@@ -1,84 +1,205 @@
-import { NotImplemented, BadRequest, MethodNotAllowed } from '../../errors/src/index.ts';
-import type { ServiceMethods, Params, Id, NullableId, Paginated } from '../../feathers/src/declarations.ts';
-import { filterQuery } from './filter-query.ts';
-
-const callMethod = (self: any, name: any, ...args: any[]) => {
- if (typeof self[name] !== 'function') {
- return Promise.reject(new NotImplemented(`Method ${name} not available`));
- }
-
- return self[name](...args);
-};
+// deno-lint-ignore-file require-await
+import { BadRequest, MethodNotAllowed } from "../../errors/mod.ts";
+import { Id, NullableId, Paginated, Query } from "../../feathers/mod.ts";
+import {
+ AdapterParams,
+ AdapterServiceOptions,
+ InternalServiceMethods,
+ PaginationOptions,
+} from "./declarations.ts";
+import { filterQuery } from "./query.ts";
const alwaysMulti: { [key: string]: boolean } = {
find: true,
get: false,
- update: false
+ update: false,
};
-export interface ServiceOptions {
- events?: string[];
- multi: boolean|string[];
- id: string;
- paginate: {
- default?: number;
- max?: number;
+/**
+ * An abstract base class that a database adapter can extend from to implement the
+ * `__find`, `__get`, `__update`, `__patch` and `__remove` methods.
+ */
+export abstract class AdapterBase<
+ T = any,
+ D = Partial,
+ P extends AdapterParams = AdapterParams,
+ O extends AdapterServiceOptions = AdapterServiceOptions
+> implements InternalServiceMethods
+{
+ options: O;
+
+ constructor(options: O) {
+ this.options = {
+ id: "id",
+ events: [],
+ paginate: false,
+ multi: false,
+ filters: {},
+ operators: [],
+ ...options,
+ };
}
- whitelist?: string[];
- allow: string[];
- filters: string[];
-}
-export interface AdapterOptions extends Pick {
- Model?: M;
-}
+ get id() {
+ return this.options.id;
+ }
-export interface AdapterParams extends Params {
- adapter?: Partial>;
-}
+ get events() {
+ return this.options.events;
+ }
-/**
- * Hook-less (internal) service methods. Directly call database adapter service methods
- * without running any service-level hooks. This can be useful if you need the raw data
- * from the service and don't want to trigger any of its hooks.
- *
- * Important: These methods are only available internally on the server, not on the client
- * side and only for the Feathers database adapters.
- *
- * These methods do not trigger events.
- *
- * @see {@link https://docs.feathersjs.com/guides/migrating.html#hook-less-service-methods}
- */
-export interface InternalServiceMethods> {
+ /**
+ * Check if this adapter allows multiple updates for a method.
+ * @param method The method name to check.
+ * @param params The service call params.
+ * @returns Wether or not multiple updates are allowed.
+ */
+ allowsMulti(method: string, params: P = {} as P) {
+ const always = alwaysMulti[method];
+
+ if (typeof always !== "undefined") {
+ return always;
+ }
+
+ const { multi } = this.getOptions(params);
+
+ if (multi === true || multi === false) {
+ return multi;
+ }
+
+ return multi?.includes(method);
+ }
/**
- * Retrieve all resources from this service, skipping any service-level hooks.
+ * Returns the combined options for a service call. Options will be merged
+ * with `this.options` and `params.adapter` for dynamic overrides.
+ *
+ * @param params The parameters for the service method call
+ * @returns The actual options for this call
+ */
+ getOptions(params: P): O {
+ const paginate =
+ params.paginate !== undefined ? params.paginate : this.options.paginate;
+
+ return {
+ ...this.options,
+ paginate,
+ ...params.adapter,
+ };
+ }
+
+ /**
+ * Sanitize the incoming data, e.g. removing invalid keywords etc.
+ *
+ * @param data The data to sanitize
+ * @param _params Service call parameters
+ * @returns The sanitized data
+ */
+ async sanitizeData>(data: X, _params?: P) {
+ return data;
+ }
+
+ /**
+ * Returns a sanitized version of `params.query`, converting filter values
+ * (like $limit and $skip) into the expected type. Will throw an error if
+ * a `$` prefixed filter or operator value that is not allowed in `filters`
+ * or `operators` is encountered.
+ *
+ * @param params The service call parameter.
+ * @returns A new object containing the sanitized query.
+ */
+ async sanitizeQuery(params: P = {} as P): Promise {
+ const options = this.getOptions(params);
+ const { query, filters } = filterQuery(params.query!, options);
+
+ return {
+ ...filters,
+ ...query,
+ };
+ }
+
+ abstract $find(
+ _params?: P & { paginate?: PaginationOptions }
+ ): Promise>;
+ abstract $find(_params?: P & { paginate: false }): Promise;
+ abstract $find(params?: P): Promise>;
+
+ /**
+ * Retrieve all resources from this service, skipping any service-level hooks but sanitize the query
+ * with allowed filters and properties by calling `sanitizeQuery`.
*
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#find-params|Feathers API Documentation: .find(params)}
*/
- _find (params?: AdapterParams): Promise>;
+ async _find(
+ _params?: P & { paginate?: PaginationOptions }
+ ): Promise>;
+ async _find(_params?: P & { paginate: false }): Promise;
+ async _find(params?: P): Promise>;
+ async _find(params?: P): Promise> {
+ const query = await this.sanitizeQuery(params);
+
+ return this.$find({
+ ...params,
+ query,
+ } as P & { paginate?: PaginationOptions | false });
+ }
+
+ abstract $get(id: Id, params?: P): Promise;
/**
- * Retrieve a single resource matching the given ID, skipping any service-level hooks.
+ * Retrieve a single resource matching the given ID, skipping any service-level hooks but sanitize the query
+ * with allowed filters and properties by calling `sanitizeQuery`.
*
* @param id - ID of the resource to locate
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}
*/
- _get (id: Id, params?: AdapterParams): Promise;
+ async _get(id: Id, params?: P): Promise {
+ const query = await this.sanitizeQuery(params);
+
+ return this.$get(id, {
+ ...params,
+ query,
+ } as P);
+ }
+
+ abstract $create(data: Partial, params?: P): Promise;
+ abstract $create(data: Partial[], params?: P): Promise;
+ abstract $create(
+ data: Partial | Partial[],
+ params?: P
+ ): Promise;
/**
- * Create a new resource for this service, skipping any service-level hooks.
+ * Create a new resource for this service, skipping any service-level hooks, sanitize the data
+ * and check if multiple updates are allowed.
*
* @param data - Data to insert into this service.
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}
*/
- _create (data: D | D[], params?: AdapterParams): Promise;
+ async _create(data: Partial, params?: P): Promise;
+ async _create(data: Partial[], params?: P): Promise;
+ async _create(data: Partial | Partial[], params?: P): Promise;
+ async _create(data: Partial | Partial[], params?: P): Promise {
+ if (Array.isArray(data) && !this.allowsMulti("create", params)) {
+ throw new MethodNotAllowed("Can not create multiple entries");
+ }
+
+ const payload = Array.isArray(data)
+ ? await Promise.all(
+ data.map((current) => this.sanitizeData(current, params))
+ )
+ : await this.sanitizeData(data, params);
+
+ return this.$create(payload, params);
+ }
+
+ abstract $update(id: Id, data: D, params?: P): Promise;
/**
* Replace any resources matching the given ID with the given data, skipping any service-level hooks.
@@ -89,10 +210,33 @@ export interface InternalServiceMethods> {
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}
*/
- _update (id: Id, data: D, params?: AdapterParams): Promise;
+ async _update(id: Id, data: D, params?: P): Promise {
+ if (id === null || Array.isArray(data)) {
+ throw new BadRequest(
+ "You can not replace multiple instances. Did you mean 'patch'?"
+ );
+ }
+
+ const payload = await this.sanitizeData(data, params);
+ const query = await this.sanitizeQuery(params);
+
+ return this.$update(id, payload, {
+ ...params,
+ query,
+ } as P);
+ }
+
+ abstract $patch(id: null, data: Partial, params?: P): Promise;
+ abstract $patch(id: Id, data: Partial, params?: P): Promise;
+ abstract $patch(
+ id: NullableId,
+ data: Partial,
+ params?: P
+ ): Promise;
/**
* Merge any resources matching the given ID with the given data, skipping any service-level hooks.
+ * Sanitizes the query and data and checks it multiple updates are allowed.
*
* @param id - ID of the resource to be patched
* @param data - Data to merge with the current resource.
@@ -100,132 +244,49 @@ export interface InternalServiceMethods> {
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}
*/
- _patch (id: NullableId, data: D, params?: AdapterParams): Promise;
+ async _patch(id: null, data: Partial, params?: P): Promise;
+ async _patch(id: Id, data: Partial, params?: P): Promise;
+ async _patch(id: NullableId, data: Partial, params?: P): Promise;
+ async _patch(id: NullableId, data: Partial, params?: P): Promise {
+ if (id === null && !this.allowsMulti("patch", params)) {
+ throw new MethodNotAllowed("Can not patch multiple entries");
+ }
+
+ const { $limit, ...query } = await this.sanitizeQuery(params);
+ const payload = await this.sanitizeData(data, params);
+
+ return this.$patch(id, payload, {
+ ...params,
+ query,
+ } as P);
+ }
+
+ abstract $remove(id: null, params?: P): Promise;
+ abstract $remove(id: Id, params?: P): Promise;
+ abstract $remove(id: NullableId, params?: P): Promise;
/**
* Remove resources matching the given ID from the this service, skipping any service-level hooks.
+ * Sanitized the query and verifies that multiple updates are allowed.
*
* @param id - ID of the resource to be removed
* @param params - Service call parameters {@link Params}
* @see {@link HookLessServiceMethods}
* @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}
*/
- _remove (id: NullableId, params?: AdapterParams): Promise;
-}
-
-export class AdapterService<
- T = any,
- D = Partial,
- O extends Partial = Partial
-> implements ServiceMethods, D> {
- options: ServiceOptions & O;
-
- constructor (options: O) {
- this.options = Object.assign({
- id: 'id',
- events: [],
- paginate: {},
- multi: false,
- filters: [],
- allow: []
- }, options);
- }
-
- get id () {
- return this.options.id;
- }
-
- get events () {
- return this.options.events;
- }
-
- filterQuery (params: AdapterParams = {}, opts: any = {}) {
- const paginate = typeof params.paginate !== 'undefined'
- ? params.paginate
- : this.getOptions(params).paginate;
- const { query = {} } = params;
- const options = Object.assign({
- operators: this.options.whitelist || this.options.allow || [],
- filters: this.options.filters,
- paginate
- }, opts);
- const result = filterQuery(query, options);
-
- return Object.assign(result, { paginate });
- }
-
- allowsMulti (method: string, params: AdapterParams = {}) {
- const always = alwaysMulti[method];
-
- if (typeof always !== 'undefined') {
- return always;
- }
-
- const { multi: option } = this.getOptions(params);
-
- if (option === true || option === false) {
- return option;
- }
-
- return option.includes(method);
- }
-
- getOptions (params: AdapterParams): ServiceOptions & { model?: any } {
- return {
- ...this.options,
- ...params.adapter
- }
- }
-
- find (params?: AdapterParams): Promise> {
- return callMethod(this, '_find', params);
- }
-
- get (id: Id, params?: AdapterParams): Promise {
- return callMethod(this, '_get', id, params);
- }
-
- create (data: Partial, params?: AdapterParams): Promise;
- create (data: Partial[], params?: AdapterParams): Promise;
- create (data: Partial | Partial[], params?: AdapterParams): Promise {
- if (Array.isArray(data) && !this.allowsMulti('create', params)) {
- return Promise.reject(new MethodNotAllowed('Can not create multiple entries'));
+ async _remove(id: null, params?: P): Promise;
+ async _remove(id: Id, params?: P): Promise;
+ async _remove(id: NullableId, params?: P): Promise;
+ async _remove(id: NullableId, params?: P): Promise {
+ if (id === null && !this.allowsMulti("remove", params)) {
+ throw new MethodNotAllowed("Can not remove multiple entries");
}
- return callMethod(this, '_create', data, params);
- }
-
- update (id: Id, data: D, params?: AdapterParams): Promise {
- if (id === null || Array.isArray(data)) {
- return Promise.reject(new BadRequest(
- 'You can not replace multiple instances. Did you mean \'patch\'?'
- ));
- }
+ const { $limit, ...query } = await this.sanitizeQuery(params);
- return callMethod(this, '_update', id, data, params);
+ return this.$remove(id, {
+ ...params,
+ query,
+ } as P);
}
-
- patch (id: Id, data: Partial, params?: AdapterParams): Promise;
- patch (id: null, data: Partial, params?: AdapterParams): Promise;
- patch (id: NullableId, data: Partial, params?: AdapterParams): Promise;
- patch (id: NullableId, data: Partial, params?: AdapterParams): Promise {
- if (id === null && !this.allowsMulti('patch', params)) {
- return Promise.reject(new MethodNotAllowed('Can not patch multiple entries'));
- }
-
- return callMethod(this, '_patch', id, data, params);
- }
-
- remove (id: Id, params?: AdapterParams): Promise;
- remove (id: null, params?: AdapterParams): Promise;
- remove (id: NullableId, params?: AdapterParams): Promise;
- remove (id: NullableId, params?: AdapterParams): Promise {
- if (id === null && !this.allowsMulti('remove', params)) {
- return Promise.reject(new MethodNotAllowed('Can not remove multiple entries'));
- }
-
- return callMethod(this, '_remove', id, params);
- }
-
- async setup () {}
}
diff --git a/main/adapter-commons/src/sort.ts b/main/adapter-commons/src/sort.ts
index 0781c61d8d..281c197397 100644
--- a/main/adapter-commons/src/sort.ts
+++ b/main/adapter-commons/src/sort.ts
@@ -1,64 +1,104 @@
// Sorting algorithm taken from NeDB (https://github.com/louischatriot/nedb)
// See https://github.com/louischatriot/nedb/blob/e3f0078499aa1005a59d0c2372e425ab789145c1/lib/model.js#L189
-function compareNSB (a: any, b: any): 0 | 1 | -1 {
- if (a < b) { return -1; }
- if (a > b) { return 1; }
+export function compareNSB(a: any, b: any) {
+ if (a < b) {
+ return -1;
+ }
+ if (a > b) {
+ return 1;
+ }
return 0;
}
-function compareArrays (a: any, b: any) {
- let i;
- let comp;
+export function compareArrays(a: any[], b: any[]) {
+ for (let i = 0, l = Math.min(a.length, b.length); i < l; i++) {
+ const comparison = compare(a[i], b[i]);
- for (i = 0; i < Math.min(a.length, b.length); i += 1) {
- comp = compare(a[i], b[i]);
-
- if (comp !== 0) { return comp; }
+ if (comparison !== 0) {
+ return comparison;
+ }
}
// Common section was identical, longest one wins
return compareNSB(a.length, b.length);
}
-function compare (a: any, b: any, compareStrings: any = compareNSB): any {
+export function compare(
+ a: any,
+ b: any,
+ compareStrings: any = compareNSB
+): 0 | 1 | -1 {
+ if (a === b) {
+ return 0;
+ }
+
// undefined
- if (a === undefined) { return b === undefined ? 0 : -1; }
- if (b === undefined) { return a === undefined ? 0 : 1; }
+ if (a === undefined) {
+ return -1;
+ }
+ if (b === undefined) {
+ return 1;
+ }
// null
- if (a === null) { return b === null ? 0 : -1; }
- if (b === null) { return a === null ? 0 : 1; }
+ if (a === null) {
+ return -1;
+ }
+ if (b === null) {
+ return 1;
+ }
// Numbers
- if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; }
- if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; }
+ if (typeof a === "number") {
+ return typeof b === "number" ? compareNSB(a, b) : -1;
+ }
+ if (typeof b === "number") {
+ return 1;
+ }
// Strings
- if (typeof a === 'string') { return typeof b === 'string' ? compareStrings(a, b) : -1; }
- if (typeof b === 'string') { return typeof a === 'string' ? compareStrings(a, b) : 1; }
+ if (typeof a === "string") {
+ return typeof b === "string" ? compareStrings(a, b) : -1;
+ }
+ if (typeof b === "string") {
+ return 1;
+ }
// Booleans
- if (typeof a === 'boolean') { return typeof b === 'boolean' ? compareNSB(a, b) : -1; }
- if (typeof b === 'boolean') { return typeof a === 'boolean' ? compareNSB(a, b) : 1; }
+ if (typeof a === "boolean") {
+ return typeof b === "boolean" ? compareNSB(a, b) : -1;
+ }
+ if (typeof b === "boolean") {
+ return 1;
+ }
// Dates
- if (a instanceof Date) { return b instanceof Date ? compareNSB(a.getTime(), b.getTime()) : -1; }
- if (b instanceof Date) { return a instanceof Date ? compareNSB(a.getTime(), b.getTime()) : 1; }
+ if (a instanceof Date) {
+ return b instanceof Date ? compareNSB(a.getTime(), b.getTime()) : -1;
+ }
+ if (b instanceof Date) {
+ return 1;
+ }
// Arrays (first element is most significant and so on)
- if (Array.isArray(a)) { return Array.isArray(b) ? compareArrays(a, b) : -1; }
- if (Array.isArray(b)) { return Array.isArray(a) ? compareArrays(a, b) : 1; }
+ if (Array.isArray(a)) {
+ return Array.isArray(b) ? compareArrays(a, b) : -1;
+ }
+ if (Array.isArray(b)) {
+ return 1;
+ }
// Objects
const aKeys = Object.keys(a).sort();
const bKeys = Object.keys(b).sort();
- let comp = 0;
- for (let i = 0; i < Math.min(aKeys.length, bKeys.length); i += 1) {
- comp = compare(a[aKeys[i]], b[bKeys[i]]);
+ for (let i = 0, l = Math.min(aKeys.length, bKeys.length); i < l; i++) {
+ const comparison = compare(a[aKeys[i]], b[bKeys[i]]);
- if (comp !== 0) { return comp; }
+ if (comparison !== 0) {
+ return comparison;
+ }
}
return compareNSB(aKeys.length, bKeys.length);
@@ -66,45 +106,31 @@ function compare (a: any, b: any, compareStrings: any = compareNSB): any {
// An in-memory sorting function according to the
// $sort special query parameter
-export function sorter ($sort: any) {
- let sortLevels = 0; // > 0 if $sort has tags with '.' i.e. '{a: 1, b: -1, "c.x.z": 1}'
-
- const getVal = (a: any, sortKeys: any[]) => {
- const keys = sortKeys.map(key => key);
- let val = a;
- do {
- const key = keys.shift();
- val = val[key];
- } while (keys.length);
-
- return val;
- };
+export function sorter($sort: { [key: string]: -1 | 1 }) {
+ const get = (value: any, path: string[]) =>
+ path.reduce((value, key) => value[key], value);
- const criteria = Object.keys($sort).map(key => {
+ const compares = Object.keys($sort).map((key) => {
const direction = $sort[key];
- const keys = key.split('.');
- sortLevels += (keys.length > 1) ? 1 : 0;
+ const path = key.split(".");
- return { keys, direction };
+ if (path.length === 1) {
+ return (a: any, b: any) => direction * compare(a[key], b[key]);
+ } else {
+ return (a: any, b: any) =>
+ direction * compare(get(a, path), get(b, path));
+ }
});
return function (a: any, b: any) {
- let compared;
+ for (const compare of compares) {
+ const comparasion = compare(a, b);
- for (const criterion of criteria) {
- if (sortLevels) {
- compared = criterion.direction * compare(getVal(a, criterion.keys), getVal(b, criterion.keys));
- } else {
- compared = criterion.direction * compare(a[criterion.keys[0]], b[criterion.keys[0]]);
- }
-
- if (compared !== 0) {
- return compared;
+ if (comparasion !== 0) {
+ return comparasion;
}
}
return 0;
};
}
-
-export { compareNSB, compareArrays, compare }
\ No newline at end of file
diff --git a/main/adapter-commons/test/commons.test.ts b/main/adapter-commons/test/commons.test.ts
index 5ecc9a6b7f..353eafdb43 100644
--- a/main/adapter-commons/test/commons.test.ts
+++ b/main/adapter-commons/test/commons.test.ts
@@ -1,67 +1,96 @@
-import { it, assertEquals } from '../../commons/src/index.ts'
-import { select } from '../src/index.ts';
+import {
+ describe,
+ it,
+ assertStrictEquals,
+ assertEquals,
+} from "../../commons/mod.ts";
+import { select } from "../mod.ts";
-it('adapter-commons: select', () => {
- const selector = select({
- query: { $select: ['name', 'age'] }
- });
+describe("@feathersjs/adapter-commons", () => {
+ describe("select", () => {
+ it("select", () => {
+ const selector = select({
+ query: { $select: ["name", "age"] },
+ });
- return Promise.resolve({
- name: 'David',
- age: 3,
- test: 'me'
- }).then(selector).then(result => assertEquals(result, {
- name: 'David',
- age: 3
- }));
-});
+ return Promise.resolve({
+ name: "David",
+ age: 3,
+ test: "me",
+ })
+ .then(selector)
+ .then((result) =>
+ assertEquals(result, {
+ name: "David",
+ age: 3,
+ })
+ );
+ });
-it('adapter-commons: select with arrays', () => {
- const selector = select({
- query: { $select: ['name', 'age'] }
- });
+ it("select with arrays", () => {
+ const selector = select({
+ query: { $select: ["name", "age"] },
+ });
- return Promise.resolve([{
- name: 'David',
- age: 3,
- test: 'me'
- }, {
- name: 'D',
- age: 4,
- test: 'you'
- }]).then(selector).then(result => assertEquals(result, [{
- name: 'David',
- age: 3
- }, {
- name: 'D',
- age: 4
- }]));
-});
+ return Promise.resolve([
+ {
+ name: "David",
+ age: 3,
+ test: "me",
+ },
+ {
+ name: "D",
+ age: 4,
+ test: "you",
+ },
+ ])
+ .then(selector)
+ .then((result) =>
+ assertEquals(result, [
+ {
+ name: "David",
+ age: 3,
+ },
+ {
+ name: "D",
+ age: 4,
+ },
+ ])
+ );
+ });
-it('adapter-commons: select with no query', () => {
- const selector = select({});
- const data = {
- name: 'David'
- };
+ it("select with no query", () => {
+ const selector = select({});
+ const data = {
+ name: "David",
+ };
- return Promise.resolve(data).then(selector).then(result =>
- assertEquals(result, data)
- );
-});
+ return Promise.resolve(data)
+ .then(selector)
+ .then((result) => assertStrictEquals(result, data));
+ });
-it('adapter-commons: select with other fields', () => {
- const selector = select({
- query: { $select: [ 'name' ] }
- }, 'id');
- const data = {
- id: 'me',
- name: 'David',
- age: 10
- };
+ it("select with other fields", () => {
+ const selector = select(
+ {
+ query: { $select: ["name"] },
+ },
+ "id"
+ );
+ const data = {
+ id: "me",
+ name: "David",
+ age: 10,
+ };
- return Promise.resolve(data)
- .then(selector)
- .then(result => {
- assertEquals(result, { id: 'me', name: 'David' })
+ return Promise.resolve(data)
+ .then(selector)
+ .then((result) =>
+ assertEquals(result, {
+ id: "me",
+ name: "David",
+ })
+ );
});
+ });
});
diff --git a/main/adapter-commons/test/filter-query.test.ts b/main/adapter-commons/test/filter-query.test.ts
deleted file mode 100644
index c9a971da21..0000000000
--- a/main/adapter-commons/test/filter-query.test.ts
+++ /dev/null
@@ -1,256 +0,0 @@
-import { it, assert, assertEquals, assertStrictEquals, assertThrows } from '../../commons/src/testing.ts'
-import { errors } from '../../errors/src/index.ts'
-import { objectId } from 'https://deno.land/x/objectid@0.2.0/mod.ts';
-
-import { filterQuery } from '../src/filter-query.ts';
-
-// const { ObjectId } = Bson
-const makeLimitQuery = () => ({ $limit: 1 })
-const makeSkipQuery = () => ({ $skip: 1 })
-const makeSelectQuery = () => ({ $select: 1 })
-
-// describe('@feathersjs/adapter-commons/filterQuery', () => {
-// describe('$sort', () => {
-it('returns $sort when present in query', () => {
- const originalQuery = { $sort: { name: 1 } };
- const { filters, query } = filterQuery(originalQuery);
-
- assertStrictEquals(filters.$sort.name, 1);
- assertEquals(query, {});
- assertEquals(originalQuery, {
- $sort: { name: 1 }
- }, 'does not modify original query');
-});
-
-it('returns $sort when present in query as an object', () => {
- const { filters, query } = filterQuery({ $sort: { name: { something: 10 } } });
-
- assertStrictEquals(filters.$sort.name.something, 10);
- assertEquals(query, {});
-});
-
-it('converts strings in $sort', () => {
- const { filters, query } = filterQuery({ $sort: { test: '-1' } });
-
- assertStrictEquals(filters.$sort.test, -1);
- assertEquals(query, {});
-});
-
-it('does not convert $sort arrays', () => {
- const $sort = [ [ 'test', '-1' ], [ 'a', '1' ] ];
- const { filters, query } = filterQuery({ $sort });
-
- assertEquals(filters.$sort, $sort);
- assertEquals(query, {});
-});
-
-it('throws an error when special parameter is not known', () => {
- try {
- const query = { $foo: 1 };
- filterQuery(query);
- assert(false, 'Should never get here');
- } catch (error: any) {
- assertStrictEquals(error.name, 'BadRequest');
- assertStrictEquals(error.message, 'Invalid query parameter $foo');
- }
-});
-
-it('returns undefined when not present in query', () => {
- const query = { foo: 1 };
- const { filters } = filterQuery(query);
-
- assertStrictEquals(filters.$sort, undefined);
-});
-
-it('returns $limit when present in query', () => {
- const limitQuery = makeLimitQuery()
- const { filters, query } = filterQuery(limitQuery);
-
- assertStrictEquals(filters.$limit, 1);
- assertEquals(query, {});
-});
-
-it('returns undefined when not present in query', () => {
- const query = { foo: 1 };
- const { filters } = filterQuery(query);
-
- assertStrictEquals(filters.$limit, undefined);
-});
-
-it('removes $limit from query when present', () => {
- const limitQuery = makeLimitQuery()
- assertEquals(filterQuery(limitQuery).query, {});
-});
-
-it('parses $limit strings into integers (#4)', () => {
- const { filters } = filterQuery({ $limit: '2' });
-
- assertStrictEquals(filters.$limit, 2);
-});
-
-it('allows $limit 0', () => {
- const { filters } = filterQuery({ $limit: 0 }, { default: 10 });
-
- assertStrictEquals(filters.$limit, 0);
-});
-
-// describe('pagination', () => {
-it('limits with default pagination', () => {
- const { filters } = filterQuery({}, { paginate: { default: 10 } });
-
- assertStrictEquals(filters.$limit, 10);
-});
-
-it('limits with max pagination', () => {
- const { filters } = filterQuery({ $limit: 20 }, { paginate: { default: 5, max: 10 } });
- const { filters: filtersNeg } = filterQuery({ $limit: -20 }, { paginate: { default: 5, max: 10 } });
-
- assertStrictEquals(filters.$limit, 10);
- assertStrictEquals(filtersNeg.$limit, 10);
-});
-
-it('limits with default pagination when not a number', () => {
- const { filters } = filterQuery({ $limit: 'something' }, { paginate: { default: 5, max: 10 } });
-
- assertStrictEquals(filters.$limit, 5);
-});
-
-it('limits to 0 when no paginate.default and not a number', () => {
- const { filters } = filterQuery({ $limit: 'something' }, { paginate: { max: 10 } });
-
- assertStrictEquals(filters.$limit, 0);
-});
-
-it('still uses paginate.max when there is no paginate.default (#2104)', () => {
- const { filters } = filterQuery({ $limit: 100 }, { paginate: { max: 10 } });
-
- assertStrictEquals(filters.$limit, 10);
-});
-
-// describe('$skip', () => {
-it('returns $skip when present in query', () => {
- const skipQuery = makeSkipQuery()
- const { filters } = filterQuery(skipQuery);
-
- assertStrictEquals(filters.$skip, 1);
-});
-
-it('removes $skip from query when present', () => {
- const skipQuery = makeSkipQuery()
- assertEquals(filterQuery(skipQuery).query, {});
-});
-
-it('returns undefined when not present in query', () => {
- const query = { foo: 1 };
- const { filters } = filterQuery(query);
-
- assertStrictEquals(filters.$skip, undefined);
-});
-
-it('parses $skip strings into integers (#4)', () => {
- const { filters } = filterQuery({ $skip: '33' });
-
- assertStrictEquals(filters.$skip, 33);
-});
-
-// describe('$select', () => {
-it('returns $select when present in query', () => {
- const selectQuery = makeSelectQuery()
- const { filters } = filterQuery(selectQuery);
-
- assertStrictEquals(filters.$select, 1);
-});
-
-it('removes $select from query when present', () => {
- const selectQuery = makeSelectQuery()
- assertEquals(filterQuery(selectQuery).query, {});
-});
-
-it('returns undefined when not present in query', () => {
- const query = { foo: 1 };
- const { filters } = filterQuery(query);
-
- assertStrictEquals(filters.$select, undefined);
-});
-
-it('includes Symbols', () => {
- const TEST = Symbol('testing');
- const original = {
- [TEST]: 'message',
- other: true,
- sub: { [TEST]: 'othermessage' }
- };
-
- const { query } = filterQuery(original);
-
- assertEquals(query, {
- [TEST]: 'message',
- other: true,
- sub: { [TEST]: 'othermessage' }
- });
-});
-
-it('only converts plain objects', () => {
- const userId = objectId().toString();
- const original = {
- userId
- };
-
- const { query } = filterQuery(original);
-
- assertEquals(query, original);
-});
-
-// describe('arrays', () => {
-it('validates queries in arrays', () => {
- assertThrows(
- () => {
- filterQuery({
- $or: [{ $exists: false }]
- });
- },
- errors.BadRequest,
- 'Invalid query parameter $exists'
- );
-});
-
-// describe('additional filters', () => {
-it('throw error when not set as additionals', () => {
- try {
- filterQuery({ $select: 1, $known: 1 });
- assert(false, 'Should never get here');
- } catch (error: any) {
- assertStrictEquals(error.message, 'Invalid query parameter $known');
- }
-});
-
-it('returns default and known additional filters (array)', () => {
- const query = { $select: ['a', 'b'], $known: 1, $unknown: 1 };
- const { filters } = filterQuery(query, { filters: [ '$known', '$unknown' ] });
-
- assertStrictEquals(filters.$unknown, 1);
- assertStrictEquals(filters.$known, 1);
- assertEquals(filters.$select, [ 'a', 'b' ]);
-});
-
-it('returns default and known additional filters (object)', () => {
- const { filters } = filterQuery({
- $known: 1,
- $select: 1
- }, { filters: { $known: (value: any) => value.toString() } });
-
- assertStrictEquals(filters.$unknown, undefined);
- assertStrictEquals(filters.$known, '1');
- assertStrictEquals(filters.$select, 1);
-});
-
-// describe('additional operators', () => {
-it('returns query with default and known additional operators', () => {
- const { query } = filterQuery({
- $ne: 1, $known: 1
- }, { operators: [ '$known' ] });
-
- assertStrictEquals(query.$ne, 1);
- assertStrictEquals(query.$known, 1);
- assertStrictEquals(query.$unknown, undefined);
-});
diff --git a/main/adapter-commons/test/fixture.ts b/main/adapter-commons/test/fixture.ts
new file mode 100644
index 0000000000..08f3442493
--- /dev/null
+++ b/main/adapter-commons/test/fixture.ts
@@ -0,0 +1,129 @@
+// deno-lint-ignore-file require-await
+import {
+ AdapterBase,
+ AdapterParams,
+ InternalServiceMethods,
+ PaginationOptions,
+} from "../mod.ts";
+import { Id, NullableId, Paginated } from "../../feathers/mod.ts";
+
+export type Data = {
+ id: Id;
+};
+
+export class MethodBase
+ extends AdapterBase, AdapterParams>
+ implements InternalServiceMethods
+{
+ async $find(
+ _params?: AdapterParams & { paginate?: PaginationOptions }
+ ): Promise>;
+ async $find(_params?: AdapterParams & { paginate: false }): Promise;
+ async $find(params?: AdapterParams): Promise>;
+ async $find(
+ params?: AdapterParams
+ ): Promise> {
+ if (params && params.paginate === false) {
+ return {
+ total: 0,
+ limit: 10,
+ skip: 0,
+ data: [],
+ };
+ }
+
+ return [];
+ }
+
+ async $get(id: Id, _params?: AdapterParams): Promise {
+ return { id };
+ }
+
+ async $create(
+ data: Partial[],
+ _params?: AdapterParams
+ ): Promise;
+ async $create(data: Partial, _params?: AdapterParams): Promise;
+ async $create(
+ data: Partial | Partial[],
+ _params?: AdapterParams
+ ): Promise {
+ if (Array.isArray(data)) {
+ return [
+ {
+ id: "something",
+ },
+ ];
+ }
+
+ return {
+ id: "something",
+ ...data,
+ };
+ }
+
+ async create(
+ data: Partial | Partial[],
+ params?: AdapterParams
+ ): Promise {
+ return this._create(data, params);
+ }
+
+ async $update(id: NullableId, _data: Data, _params?: AdapterParams) {
+ return Promise.resolve({ id } as Data);
+ }
+
+ async $patch(
+ id: null,
+ _data: Partial,
+ _params?: AdapterParams
+ ): Promise;
+ async $patch(
+ id: Id,
+ _data: Partial,
+ _params?: AdapterParams
+ ): Promise;
+ async $patch(
+ id: NullableId,
+ _data: Partial,
+ _params?: AdapterParams
+ ): Promise {
+ if (id === null) {
+ return [];
+ }
+
+ return { id };
+ }
+
+ async $remove(id: null, _params?: AdapterParams): Promise;
+ async $remove(id: Id, _params?: AdapterParams): Promise;
+ async $remove(id: NullableId, _params?: AdapterParams) {
+ if (id === null) {
+ return [] as Data[];
+ }
+
+ return { id };
+ }
+}
+
+export class MethodService extends MethodBase {
+ find(params?: AdapterParams): Promise> {
+ return this._find(params);
+ }
+
+ get(id: Id, params?: AdapterParams): Promise {
+ return this._get(id, params);
+ }
+
+ async update(id: Id, data: Data, params?: AdapterParams) {
+ return this._update(id, data, params);
+ }
+
+ async patch(id: NullableId, data: Partial, params?: AdapterParams) {
+ return this._patch(id, data, params);
+ }
+
+ async remove(id: NullableId, params?: AdapterParams) {
+ return this._remove(id, params);
+ }
+}
diff --git a/main/adapter-commons/test/query.test.ts b/main/adapter-commons/test/query.test.ts
new file mode 100644
index 0000000000..af255cbed9
--- /dev/null
+++ b/main/adapter-commons/test/query.test.ts
@@ -0,0 +1,336 @@
+import {
+ describe,
+ it,
+ assertStrictEquals,
+ unreachable,
+ beforeEach,
+ assertThrows,
+ assertEquals,
+} from "../../commons/mod.ts";
+import { ObjectId } from "https://deno.land/x/mongo@v0.31.1/mod.ts";
+import { filterQuery } from "../mod.ts";
+import { BadRequest } from "../../errors/mod.ts";
+
+describe("@feathersjs/adapter-commons/filterQuery", () => {
+ describe("$sort", () => {
+ it("returns $sort when present in query", () => {
+ const originalQuery = { $sort: { name: 1 } };
+ const { filters, query } = filterQuery(originalQuery);
+
+ assertStrictEquals(filters.$sort.name, 1);
+ assertEquals(query, {});
+ assertEquals(
+ originalQuery,
+ {
+ $sort: { name: 1 },
+ },
+ "does not modify original query"
+ );
+ });
+
+ it("returns $sort when present in query as an object", () => {
+ const { filters, query } = filterQuery({
+ $sort: { name: { something: 10 } },
+ });
+
+ assertStrictEquals(filters.$sort.name.something, 10);
+ assertEquals(query, {});
+ });
+
+ it("converts strings in $sort", () => {
+ const { filters, query } = filterQuery({ $sort: { test: "-1" } });
+
+ assertStrictEquals(filters.$sort.test, -1);
+ assertEquals(query, {});
+ });
+
+ it("does not convert $sort arrays", () => {
+ const $sort = [
+ ["test", "-1"],
+ ["a", "1"],
+ ];
+ const { filters, query } = filterQuery({ $sort });
+
+ assertStrictEquals(filters.$sort, $sort);
+ assertEquals(query, {});
+ });
+
+ it("throws an error when special parameter is not known", () => {
+ try {
+ const query = { $foo: 1 };
+ filterQuery(query);
+ unreachable();
+ } catch (error: any) {
+ assertStrictEquals(error.name, "BadRequest");
+ assertStrictEquals(error.message, "Invalid filter value $foo");
+ }
+ });
+
+ it("returns undefined when not present in query", () => {
+ const query = { foo: 1 };
+ const { filters } = filterQuery(query);
+
+ assertStrictEquals(filters.$sort, undefined);
+ });
+ });
+
+ describe("$limit", () => {
+ let testQuery: any;
+
+ beforeEach(() => {
+ testQuery = { $limit: 1 };
+ });
+
+ it("returns $limit when present in query", () => {
+ const { filters, query } = filterQuery(testQuery);
+
+ assertStrictEquals(filters.$limit, 1);
+ assertEquals(query, {});
+ });
+
+ it("returns undefined when not present in query", () => {
+ const query = { foo: 1 };
+ const { filters } = filterQuery(query);
+
+ assertStrictEquals(filters.$limit, undefined);
+ });
+
+ it("removes $limit from query when present", () => {
+ assertEquals(filterQuery(testQuery).query, {});
+ });
+
+ it("parses $limit strings into integers (#4)", () => {
+ const { filters } = filterQuery({ $limit: "2" });
+
+ assertStrictEquals(filters.$limit, 2);
+ });
+
+ it("allows $limit 0", () => {
+ const { filters } = filterQuery(
+ { $limit: 0 },
+ { paginate: { default: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 0);
+ });
+
+ describe("pagination", () => {
+ it("limits with default pagination", () => {
+ const { filters } = filterQuery({}, { paginate: { default: 10 } });
+ const { filters: filtersNeg } = filterQuery(
+ { $limit: -20 },
+ { paginate: { default: 5, max: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 10);
+ assertStrictEquals(filtersNeg.$limit, 5);
+ });
+
+ it("limits with max pagination", () => {
+ const { filters } = filterQuery(
+ { $limit: 20 },
+ { paginate: { default: 5, max: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 10);
+ });
+
+ it("limits with default pagination when not a number", () => {
+ const { filters } = filterQuery(
+ { $limit: "something" },
+ { paginate: { default: 5, max: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 5);
+ });
+
+ it("limits to 0 when no paginate.default and not a number", () => {
+ const { filters } = filterQuery(
+ { $limit: "something" },
+ { paginate: { max: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 0);
+ });
+
+ it("still uses paginate.max when there is no paginate.default (#2104)", () => {
+ const { filters } = filterQuery(
+ { $limit: 100 },
+ { paginate: { max: 10 } }
+ );
+
+ assertStrictEquals(filters.$limit, 10);
+ });
+ });
+ });
+
+ describe("$skip", () => {
+ let testQuery: any;
+
+ beforeEach(() => {
+ testQuery = { $skip: 1 };
+ });
+
+ it("returns $skip when present in query", () => {
+ const { filters } = filterQuery(testQuery);
+
+ assertStrictEquals(filters.$skip, 1);
+ });
+
+ it("removes $skip from query when present", () => {
+ assertEquals(filterQuery(testQuery).query, {});
+ });
+
+ it("returns undefined when not present in query", () => {
+ const query = { foo: 1 };
+ const { filters } = filterQuery(query);
+
+ assertStrictEquals(filters.$skip, undefined);
+ });
+
+ it("parses $skip strings into integers (#4)", () => {
+ const { filters } = filterQuery({ $skip: "33" });
+
+ assertStrictEquals(filters.$skip, 33);
+ });
+ });
+
+ describe("$select", () => {
+ let testQuery: any;
+
+ beforeEach(() => {
+ testQuery = { $select: 1 };
+ });
+
+ it("returns $select when present in query", () => {
+ const { filters } = filterQuery(testQuery);
+
+ assertStrictEquals(filters.$select, 1);
+ });
+
+ it("removes $select from query when present", () => {
+ assertEquals(filterQuery(testQuery).query, {});
+ });
+
+ it("returns undefined when not present in query", () => {
+ const query = { foo: 1 };
+ const { filters } = filterQuery(query);
+
+ assertStrictEquals(filters.$select, undefined);
+ });
+
+ it("includes Symbols", () => {
+ const TEST = Symbol("testing");
+ const original = {
+ [TEST]: "message",
+ other: true,
+ sub: { [TEST]: "othermessage" },
+ };
+
+ const { query } = filterQuery(original);
+
+ assertEquals(query, {
+ [TEST]: "message",
+ other: true,
+ sub: { [TEST]: "othermessage" },
+ });
+ });
+
+ it("only converts plain objects", () => {
+ const userId = new ObjectId();
+ const original = {
+ userId,
+ };
+
+ const { query } = filterQuery(original);
+
+ assertEquals(query, original);
+ });
+ });
+
+ describe("arrays", () => {
+ it("validates queries in arrays", () => {
+ assertThrows(
+ () => {
+ filterQuery({
+ $or: [{ $exists: false }],
+ });
+ },
+ BadRequest,
+ "Invalid query parameter $exists"
+ );
+ });
+
+ it("allows default operators in $or", () => {
+ const { filters } = filterQuery({
+ $or: [{ value: { $gte: 10 } }],
+ });
+
+ assertEquals(filters, {
+ $or: [{ value: { $gte: 10 } }],
+ });
+ });
+ });
+
+ describe("additional filters", () => {
+ it("throw error when not set as additionals", () => {
+ try {
+ filterQuery({ $select: 1, $known: 1 });
+ unreachable();
+ } catch (error: any) {
+ assertStrictEquals(error.message, "Invalid filter value $known");
+ }
+ });
+
+ it("returns default and known additional filters (array)", () => {
+ const query = { $select: ["a", "b"], $known: 1, $unknown: 1 };
+ const { filters } = filterQuery(query, {
+ filters: {
+ $known: true,
+ $unknown: true,
+ },
+ });
+
+ assertStrictEquals(filters.$unknown, 1);
+ assertStrictEquals(filters.$known, 1);
+ assertEquals(filters.$select, ["a", "b"]);
+ });
+
+ it("returns default and known additional filters (object)", () => {
+ const { filters } = filterQuery(
+ {
+ $known: 1,
+ $select: 1,
+ },
+ { filters: { $known: (value: any) => value.toString() } }
+ );
+
+ assertStrictEquals(filters.$unknown, undefined);
+ assertStrictEquals(filters.$known, "1");
+ assertStrictEquals(filters.$select, 1);
+ });
+ });
+
+ describe("additional operators", () => {
+ it("returns query with default and known additional operators", () => {
+ const { query } = filterQuery(
+ {
+ prop: { $ne: 1, $known: 1 },
+ },
+ { operators: ["$known"] }
+ );
+
+ assertEquals(query, { prop: { $ne: 1, $known: 1 } });
+ });
+
+ it("throws an error with unknown query operator", () => {
+ assertThrows(
+ () =>
+ filterQuery({
+ prop: { $unknown: "something" },
+ }),
+ "Invalid query parameter $unknown"
+ );
+ });
+ });
+});
diff --git a/main/adapter-commons/test/service.test.ts b/main/adapter-commons/test/service.test.ts
index 4e3a106cd2..303e20dcfb 100644
--- a/main/adapter-commons/test/service.test.ts
+++ b/main/adapter-commons/test/service.test.ts
@@ -1,216 +1,224 @@
-/* eslint-disable @typescript-eslint/no-unused-vars */
-import { it, assert, assertEquals, assertStrictEquals } from '../../commons/src/index.ts'
-import { NotImplemented } from '../../errors/src/index.ts';
-import { AdapterService, InternalServiceMethods } from '../src/index.ts';
-import { Params, Id, NullableId } from '../../feathers/src/declarations.ts';
-
-const METHODS = [ 'find', 'get', 'create', 'update', 'patch', 'remove' ];
-
-// describe('@feathersjs/adapter-commons/service', () => {
-class CustomService extends AdapterService {
-}
-
-// describe('errors when method does not exit', () => {
-METHODS.forEach(method => {
- it(`Undeclared Extended Methods: ${method}`, () => {
- const service = new CustomService({});
-
- // @ts-ignore suppress
- return service[method]()
- .then(() => {
- throw new Error('Should never get here');
- }).catch((error: Error) => {
- assert(error instanceof NotImplemented);
- assertStrictEquals(error.message, `Method _${method} not available`);
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/ban-ts-comment */
+import {
+ describe,
+ it,
+ assertRejects,
+ assertStrictEquals,
+ assertEquals,
+} from "../../commons/mod.ts";
+import { MethodNotAllowed } from "../../errors/mod.ts";
+import { createContext } from "../../feathers/mod.ts";
+import { MethodService } from "./fixture.ts";
+
+const METHODS: ["find", "get", "create", "update", "patch", "remove"] = [
+ "find",
+ "get",
+ "create",
+ "update",
+ "patch",
+ "remove",
+];
+
+describe("@feathersjs/adapter-commons/service", () => {
+ describe("works when methods exist", () => {
+ METHODS.forEach((method) => {
+ it(`${method}`, () => {
+ const service = new MethodService({});
+ const args = [];
+
+ if (method !== "find") {
+ args.push("test");
+ }
+
+ if (method === "update" || method === "patch") {
+ args.push({});
+ }
+
+ // @ts-ignore
+ service[method](...args);
});
- });
-});
-
-// // describe('works when methods exist', () => {
-class MethodService extends AdapterService implements InternalServiceMethods {
- _find (_params?: Params) {
- return Promise.resolve([]);
- }
-
- _get (id: Id, _params?: Params) {
- return Promise.resolve({ id });
- }
-
- _create (data: Partial | Partial[], _params?: Params) {
- return Promise.resolve(data);
- }
-
- _update (id: NullableId, _data: any, _params?: Params) {
- return Promise.resolve({ id });
- }
-
- _patch (id: NullableId, _data: any, _params?: Params) {
- return Promise.resolve({ id });
- }
-
- _remove (id: NullableId, _params?: Params) {
- return Promise.resolve({ id });
- }
-}
-
-METHODS.forEach(method => {
- it(`Internal Methods: ${method}`, () => {
- const service = new MethodService({});
- const args = [];
-
- if (method !== 'find') {
- args.push('test');
- }
-
- if (method === 'update' || method === 'patch') {
- args.push({});
- }
-
- // @ts-ignore suppress
- return service[method](...args);
- });
-});
-
-it('does not allow multi patch', () => {
- const service = new MethodService({});
-
- return service.patch(null, {})
- .then(() => assert(false))
- .catch(error => {
- assertStrictEquals(error.name, 'MethodNotAllowed');
- assertStrictEquals(error.message, 'Can not patch multiple entries');
});
-});
-it('does not allow multi remove', () => {
- const service = new MethodService({});
+ it("does not allow multi patch", async () => {
+ const service = new MethodService({});
- return service.remove(null, {})
- .then(() => assert(false))
- .catch(error => {
- assertStrictEquals(error.name, 'MethodNotAllowed');
- assertStrictEquals(error.message, 'Can not remove multiple entries');
+ await assertRejects(
+ () => service.patch(null, {}),
+ MethodNotAllowed,
+ "Can not patch multiple entries"
+ );
});
-});
-it('does not allow multi create', () => {
- const service = new MethodService({});
+ it("does not allow multi remove", async () => {
+ const service = new MethodService({});
- return service.create([])
- .then(() => assert(false))
- .catch(error => {
- assertStrictEquals(error.name, 'MethodNotAllowed');
- assertStrictEquals(error.message, 'Can not create multiple entries');
+ await assertRejects(
+ () => service.remove(null, {}),
+ MethodNotAllowed,
+ "Can not remove multiple entries"
+ );
});
-});
-it('multi can be set to true', () => {
- const service = new MethodService({});
+ it("does not allow multi create", async () => {
+ const service = new MethodService({});
- service.options.multi = true;
+ await assertRejects(
+ () => service.create([], {}),
+ MethodNotAllowed,
+ "Can not create multiple entries"
+ );
+ });
- return service.create([])
- .then(() => assert(true));
-});
+ it("multi can be set to true", async () => {
+ const service = new MethodService({});
-it('filterQuery', () => {
- const service = new CustomService({
- whitelist: [ '$something' ]
- });
- const filtered = service.filterQuery({
- query: { $limit: 10, test: 'me' }
- });
+ service.options.multi = true;
- assertEquals(filtered, {
- paginate: {},
- filters: { $limit: 10 },
- query: { test: 'me' }
+ await service.create([]);
+ });
});
- const withWhitelisted = service.filterQuery({
- query: { $limit: 10, $something: 'else' }
- });
+ it("sanitizeQuery", async () => {
+ const service = new MethodService({
+ filters: {
+ $something: true,
+ },
+ operators: ["$test"],
+ });
- assertEquals(withWhitelisted, {
- paginate: {},
- filters: { $limit: 10 },
- query: { $something: 'else' }
+ assertEquals(
+ await service.sanitizeQuery({
+ // @ts-ignore
+ query: { $limit: "10", test: "me" },
+ }),
+ { $limit: 10, test: "me" }
+ );
+
+ assertEquals(
+ await service.sanitizeQuery({
+ adapter: {
+ paginate: { max: 2 },
+ },
+ query: { $limit: "10", test: "me" } as any,
+ }),
+ { $limit: 2, test: "me" }
+ );
+
+ await assertRejects(
+ () =>
+ service.sanitizeQuery({
+ query: { name: { $bla: "me" } },
+ }),
+ "Invalid query parameter $bla"
+ );
+
+ assertEquals(
+ await service.sanitizeQuery({
+ adapter: {
+ operators: ["$bla"],
+ },
+ query: { name: { $bla: "Dave" } },
+ }),
+ { name: { $bla: "Dave" } }
+ );
});
-});
-it('getOptions', () => {
- const service = new AdapterService({
- multi: true
- });
- const opts = service.getOptions({
- adapter: {
- multi: [ 'create' ],
+ it("getOptions", () => {
+ const service = new MethodService({
+ multi: true,
paginate: {
- default: 10,
- max: 100
- }
- }
- });
+ default: 1,
+ max: 10,
+ },
+ });
+ const opts = service.getOptions({
+ adapter: {
+ multi: ["create"],
+ paginate: {
+ default: 10,
+ max: 100,
+ },
+ },
+ });
- assertEquals(opts, {
- id: 'id',
- events: [],
- paginate: { default: 10, max: 100 },
- multi: [ 'create' ],
- filters: [],
- allow: []
+ assertEquals(opts, {
+ id: "id",
+ events: [],
+ paginate: { default: 10, max: 100 },
+ multi: ["create"],
+ filters: {},
+ operators: [],
+ });
+
+ const notPaginated = service.getOptions({
+ paginate: false,
+ });
+
+ assertEquals(notPaginated, {
+ id: "id",
+ events: [],
+ paginate: false,
+ multi: true,
+ filters: {},
+ operators: [],
+ });
});
-});
-// 'allowsMulti with true'
-const allowsMultiWithTrueService = new AdapterService({multi: true});
+ describe("allowsMulti", () => {
+ describe("with true", () => {
+ const service = new MethodService({ multi: true });
-it('allowsMulti with true: returns true for multiple methods', () => {
- assertStrictEquals(allowsMultiWithTrueService.allowsMulti('patch'), true);
-});
+ it("does return true for multiple methodes", () => {
+ assertEquals(service.allowsMulti("patch"), true);
+ });
-it('allowsMulti with true: returns false for always non-multiple methods', () => {
- assertStrictEquals(allowsMultiWithTrueService.allowsMulti('update'), false);
-});
+ it("does return false for always non-multiple methodes", () => {
+ assertEquals(service.allowsMulti("update"), false);
+ });
-it('allowsMulti with true: returns true for unknown methods', () => {
- assertStrictEquals(allowsMultiWithTrueService.allowsMulti('other'), true);
-});
+ it("does return true for unknown methods", () => {
+ assertEquals(service.allowsMulti("other"), true);
+ });
+ });
-// 'allowsMulti with false'
-const multiWithFalseService = new AdapterService({multi: false});
+ describe("with false", () => {
+ const service = new MethodService({ multi: false });
-it('allowsMulti with false: returns false for multiple methods', () => {
- assertStrictEquals(multiWithFalseService.allowsMulti('remove'), false);
-});
+ it("does return false for multiple methodes", () => {
+ assertEquals(service.allowsMulti("remove"), false);
+ });
-it('allowsMulti with false: returns true for always multiple methods', () => {
- assertStrictEquals(multiWithFalseService.allowsMulti('find'), true);
-});
+ it("does return true for always multiple methodes", () => {
+ assertEquals(service.allowsMulti("find"), true);
+ });
-it('allowsMulti with false: returns false for unknown methods', () => {
- assertStrictEquals(multiWithFalseService.allowsMulti('other'), false);
-});
+ it("does return false for unknown methods", () => {
+ assertEquals(service.allowsMulti("other"), false);
+ });
+ });
-// 'allowsMulti with array'
-const multiArrayService = new AdapterService({multi: ['create', 'get', 'other']});
+ describe("with array", () => {
+ const service = new MethodService({ multi: ["create", "get", "other"] });
-it('allowsMulti with array: returns true for specified multiple methods', () => {
- assertStrictEquals(multiArrayService.allowsMulti('create'), true);
-});
+ it("does return true for specified multiple methodes", () => {
+ assertEquals(service.allowsMulti("create"), true);
+ });
-it('allowsMulti with array: returns false for non-specified multiple methods', () => {
- assertStrictEquals(multiArrayService.allowsMulti('patch'), false);
-});
+ it("does return false for non-specified multiple methodes", () => {
+ assertEquals(service.allowsMulti("patch"), false);
+ });
-it('allowsMulti with array: returns false for specified always multiple methods', () => {
- assertStrictEquals(multiArrayService.allowsMulti('get'), false);
-});
+ it("does return false for specified always multiple methodes", () => {
+ assertEquals(service.allowsMulti("get"), false);
+ });
-it('allowsMulti with array: returns true for specified unknown methods', () => {
- assertStrictEquals(multiArrayService.allowsMulti('other'), true);
-});
+ it("does return true for specified unknown methodes", () => {
+ assertEquals(service.allowsMulti("other"), true);
+ });
-it('allowsMulti with array: returns false for non-specified unknown methods', () => {
- assertStrictEquals(multiArrayService.allowsMulti('another'), false);
+ it("does return false for non-specified unknown methodes", () => {
+ assertEquals(service.allowsMulti("another"), false);
+ });
+ });
+ });
});
diff --git a/main/adapter-commons/test/sort.test.ts b/main/adapter-commons/test/sort.test.ts
index ad40afd6d9..5c768ecf58 100644
--- a/main/adapter-commons/test/sort.test.ts
+++ b/main/adapter-commons/test/sort.test.ts
@@ -1,289 +1,390 @@
-import { it, assertEquals, assert } from '../../commons/src/testing.ts'
-import { sorter } from '../src/index.ts';
-
-// describe('sorter', () => {
-it('simple sorter', () => {
- const array = [{
- name: 'David'
- }, {
- name: 'Eric'
- }];
-
- const sort = sorter({
- name: -1
- });
+import {
+ describe,
+ it,
+ assertStrictEquals,
+ beforeEach,
+ assertEquals,
+} from "../../commons/mod.ts";
+import { sorter } from "../mod.ts";
- assertEquals(array.sort(sort), [{
- name: 'Eric'
- }, {
- name: 'David'
- }]);
-});
+describe("@feathersjs/adapter-commons", () => {
+ describe("sorter", () => {
+ it("simple sorter", () => {
+ const array = [
+ {
+ name: "David",
+ },
+ {
+ name: "Eric",
+ },
+ ];
-it('simple sorter with arrays', () => {
- const array = [{
- names: [ 'a', 'b' ]
- }, {
- names: [ 'c', 'd' ]
- }];
+ const sort = sorter({
+ name: -1,
+ });
- const sort = sorter({
- names: -1
- });
+ assertEquals(array.sort(sort), [
+ {
+ name: "Eric",
+ },
+ {
+ name: "David",
+ },
+ ]);
+ });
- assertEquals(array.sort(sort), [{
- names: [ 'c', 'd' ]
- }, {
- names: [ 'a', 'b' ]
- }]);
-});
+ it("simple sorter with arrays", () => {
+ const array = [
+ {
+ names: ["a", "b"],
+ },
+ {
+ names: ["c", "d"],
+ },
+ ];
-it('simple sorter with objects', () => {
- const array = [{
- names: {
- first: 'Dave',
- last: 'L'
- }
- }, {
- names: {
- first: 'A',
- last: 'B'
- }
- }];
-
- const sort = sorter({
- names: 1
- });
+ const sort = sorter({
+ names: -1,
+ });
- assertEquals(array.sort(sort), [{
- names: {
- first: 'A',
- last: 'B'
- }
- }, {
- names: {
- first: 'Dave',
- last: 'L'
- }
- }]);
-});
+ assertEquals(array.sort(sort), [
+ {
+ names: ["c", "d"],
+ },
+ {
+ names: ["a", "b"],
+ },
+ ]);
+ });
-it('two property sorter', () => {
- const array = [{
- name: 'David',
- counter: 0
- }, {
- name: 'Eric',
- counter: 1
- }, {
- name: 'David',
- counter: 1
- }, {
- name: 'Eric',
- counter: 0
- }];
-
- const sort = sorter({
- name: -1,
- counter: 1
- });
+ it("simple sorter with objects", () => {
+ const array = [
+ {
+ names: {
+ first: "Dave",
+ last: "L",
+ },
+ },
+ {
+ names: {
+ first: "A",
+ last: "B",
+ },
+ },
+ ];
- assertEquals(array.sort(sort), [
- { name: 'Eric', counter: 0 },
- { name: 'Eric', counter: 1 },
- { name: 'David', counter: 0 },
- { name: 'David', counter: 1 }
- ]);
-});
+ const sort = sorter({
+ names: 1,
+ });
-it('two property sorter with names', () => {
- const array = [{
- name: 'David',
- counter: 0
- }, {
- name: 'Eric',
- counter: 1
- }, {
- name: 'Andrew',
- counter: 1
- }, {
- name: 'David',
- counter: 1
- }, {
- name: 'Andrew',
- counter: 0
- }, {
- name: 'Eric',
- counter: 0
- }];
-
- const sort = sorter({
- name: -1,
- counter: 1
- });
+ assertEquals(array.sort(sort), [
+ {
+ names: {
+ first: "A",
+ last: "B",
+ },
+ },
+ {
+ names: {
+ first: "Dave",
+ last: "L",
+ },
+ },
+ ]);
+ });
- assertEquals(array.sort(sort), [
- { name: 'Eric', counter: 0 },
- { name: 'Eric', counter: 1 },
- { name: 'David', counter: 0 },
- { name: 'David', counter: 1 },
- { name: 'Andrew', counter: 0 },
- { name: 'Andrew', counter: 1 }
- ]);
-});
+ it("two property sorter", () => {
+ const array = [
+ {
+ name: "David",
+ counter: 0,
+ },
+ {
+ name: "Eric",
+ counter: 1,
+ },
+ {
+ name: "David",
+ counter: 1,
+ },
+ {
+ name: "Eric",
+ counter: 0,
+ },
+ ];
-it('three property sorter with names', () => {
- const array = [{
- name: 'David',
- counter: 0,
- age: 2
- }, {
- name: 'Eric',
- counter: 1,
- age: 2
- }, {
- name: 'David',
- counter: 1,
- age: 1
- }, {
- name: 'Eric',
- counter: 0,
- age: 1
- }, {
- name: 'Andrew',
- counter: 0,
- age: 2
- }, {
- name: 'Andrew',
- counter: 0,
- age: 1
- }];
-
- const sort = sorter({
- name: -1,
- counter: 1,
- age: -1
- });
+ const sort = sorter({
+ name: -1,
+ counter: 1,
+ });
- assertEquals(array.sort(sort), [
- { name: 'Eric', counter: 0, age: 1 },
- { name: 'Eric', counter: 1, age: 2 },
- { name: 'David', counter: 0, age: 2 },
- { name: 'David', counter: 1, age: 1 },
- { name: 'Andrew', counter: 0, age: 2 },
- { name: 'Andrew', counter: 0, age: 1 }
- ]);
-});
+ assertEquals(array.sort(sort), [
+ { name: "Eric", counter: 0 },
+ { name: "Eric", counter: 1 },
+ { name: "David", counter: 0 },
+ { name: "David", counter: 1 },
+ ]);
+ });
-// describe('sorter mongoDB-like sorting on embedded objects', () => {
-const makeData = () => ([
-{ _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
-{ _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 },
-{ _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 },
-{ _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
-{ _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
-{ _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 }
-])
-
-it('straight test', () => {
- const data = makeData()
- const sort = sorter({
- amount: -1
- });
+ it("two property sorter with names", () => {
+ const array = [
+ {
+ name: "David",
+ counter: 0,
+ },
+ {
+ name: "Eric",
+ counter: 1,
+ },
+ {
+ name: "Andrew",
+ counter: 1,
+ },
+ {
+ name: "David",
+ counter: 1,
+ },
+ {
+ name: "Andrew",
+ counter: 0,
+ },
+ {
+ name: "Eric",
+ counter: 0,
+ },
+ ];
- assertEquals(data.sort(sort), [
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 }
- ]);
-});
+ const sort = sorter({
+ name: -1,
+ counter: 1,
+ });
-it('embedded sort 1', () => {
- const data = makeData()
- const sort = sorter({
- 'item.category': 1,
- 'item.type': 1
- });
+ assertEquals(array.sort(sort), [
+ { name: "Eric", counter: 0 },
+ { name: "Eric", counter: 1 },
+ { name: "David", counter: 0 },
+ { name: "David", counter: 1 },
+ { name: "Andrew", counter: 0 },
+ { name: "Andrew", counter: 1 },
+ ]);
+ });
- assertEquals(data.sort(sort), [
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 }
- ]);
-});
+ it("three property sorter with names", () => {
+ const array = [
+ {
+ name: "David",
+ counter: 0,
+ age: 2,
+ },
+ {
+ name: "Eric",
+ counter: 1,
+ age: 2,
+ },
+ {
+ name: "David",
+ counter: 1,
+ age: 1,
+ },
+ {
+ name: "Eric",
+ counter: 0,
+ age: 1,
+ },
+ {
+ name: "Andrew",
+ counter: 0,
+ age: 2,
+ },
+ {
+ name: "Andrew",
+ counter: 0,
+ age: 1,
+ },
+ ];
-it('embedded sort 2', () => {
- const data = makeData()
- const sort = sorter({
- 'item.category': 1,
- 'item.type': 1,
- amount: 1
+ const sort = sorter({
+ name: -1,
+ counter: 1,
+ age: -1,
+ });
+
+ assertEquals(array.sort(sort), [
+ { name: "Eric", counter: 0, age: 1 },
+ { name: "Eric", counter: 1, age: 2 },
+ { name: "David", counter: 0, age: 2 },
+ { name: "David", counter: 1, age: 1 },
+ { name: "Andrew", counter: 0, age: 2 },
+ { name: "Andrew", counter: 0, age: 1 },
+ ]);
+ });
});
- assertEquals(data.sort(sort), [
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 },
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 }
- ]);
-});
+ describe("sorter mongoDB-like sorting on embedded objects", () => {
+ let data: any[] = [];
-it('embedded sort 3', () => {
- const data = makeData()
- const sort = sorter({
- 'item.category': 1,
- 'item.type': 1,
- amount: -1
- });
+ beforeEach(() => {
+ data = [
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ ];
+ });
- assert.deepStrictEqual(data.sort(sort), [
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 }
- ]);
-});
+ it("straight test", () => {
+ const sort = sorter({
+ amount: -1,
+ });
-it('embedded sort 4', () => {
- const data = makeData()
- const sort = sorter({
- amount: -1,
- 'item.category': 1
- });
+ assertEquals(data.sort(sort), [
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ ]);
+ });
- assert.deepStrictEqual(data.sort(sort), [
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 },
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 }
- ]);
-});
+ it("embedded sort 1", () => {
+ const sort = sorter({
+ "item.category": 1,
+ "item.type": 1,
+ });
-it('embedded sort 5', () => {
- const data = makeData()
- const sort = sorter({
- 'item.category': 1,
- amount: 1
- });
+ assertEquals(data.sort(sort), [
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ ]);
+ });
+
+ it("embedded sort 2", () => {
+ const sort = sorter({
+ "item.category": 1,
+ "item.type": 1,
+ amount: 1,
+ });
- assert.deepStrictEqual(data.sort(sort), [
- { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },
- { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },
- { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },
- { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },
- { _id: 3, item: { category: 'cookies', type: 'chocolate chip' }, amount: 15 },
- { _id: 2, item: { category: 'cookies', type: 'chocolate chip' }, amount: 50 }
- ]);
+ assertEquals(data.sort(sort), [
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ ]);
+ });
+
+ it("embedded sort 3", () => {
+ const sort = sorter({
+ "item.category": 1,
+ "item.type": 1,
+ amount: -1,
+ });
+
+ assertEquals(data.sort(sort), [
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ ]);
+ });
+
+ it("embedded sort 4", () => {
+ const sort = sorter({
+ amount: -1,
+ "item.category": 1,
+ });
+
+ assertEquals(data.sort(sort), [
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ ]);
+ });
+
+ it("embedded sort 5", () => {
+ const sort = sorter({
+ "item.category": 1,
+ amount: 1,
+ });
+
+ assertEquals(data.sort(sort), [
+ { _id: 6, item: { category: "brownies", type: "blondie" }, amount: 10 },
+ { _id: 1, item: { category: "cake", type: "chiffon" }, amount: 10 },
+ { _id: 5, item: { category: "cake", type: "carrot" }, amount: 20 },
+ { _id: 4, item: { category: "cake", type: "lemon" }, amount: 30 },
+ {
+ _id: 3,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 15,
+ },
+ {
+ _id: 2,
+ item: { category: "cookies", type: "chocolate chip" },
+ amount: 50,
+ },
+ ]);
+ });
+ });
});
diff --git a/main/adapter-tests/LICENSE b/main/adapter-tests/LICENSE
new file mode 100644
index 0000000000..59604f46f3
--- /dev/null
+++ b/main/adapter-tests/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2022 Feathers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/main/adapter-tests/README.md b/main/adapter-tests/README.md
new file mode 100644
index 0000000000..9d54b46a4c
--- /dev/null
+++ b/main/adapter-tests/README.md
@@ -0,0 +1,25 @@
+# Feathers Adapter Tests
+
+[![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)
+[![Download Status](https://img.shields.io/npm/dm/@feathersjs/adapter-commons.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/adapter-commons)
+[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)
+
+> Feathers shared database adapter test suite
+
+## About
+
+This 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.
+
+## Authors
+
+[Feathers contributors](https://github.com/feathersjs/adapter-tests/graphs/contributors)
+
+## License
+
+Copyright (c) 2022
+[Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)
+
+Licensed under the [MIT license](LICENSE).
diff --git a/main/adapter-tests/mod.ts b/main/adapter-tests/mod.ts
new file mode 100644
index 0000000000..b0dd28d7cc
--- /dev/null
+++ b/main/adapter-tests/mod.ts
@@ -0,0 +1,2 @@
+export * from "./src/index.ts";
+export { default } from "./src/index.ts";
\ No newline at end of file
diff --git a/main/adapter-tests/src/basic.ts b/main/adapter-tests/src/basic.ts
new file mode 100644
index 0000000000..fa6c3a7795
--- /dev/null
+++ b/main/adapter-tests/src/basic.ts
@@ -0,0 +1,87 @@
+import {assert, assertStrictEquals, beforeEach, describe, it} from "../../commons/mod.ts";
+import { AdapterBasicTest } from "./declarations.ts";
+
+export default (
+ test: AdapterBasicTest,
+ app: any,
+ _errors: any,
+ serviceName: string,
+ idProp: string,
+) => {
+ describe("Basic Functionality", () => {
+ let service: any;
+
+ beforeEach(() => {
+ service = app.service(serviceName);
+ });
+
+ it(".id", () => {
+ assertStrictEquals(
+ service.id,
+ idProp,
+ "id property is set to expected name",
+ );
+ });
+
+ test(".options", () => {
+ assert(service.options, "Options are available in service.options");
+ });
+
+ test(".events", () => {
+ assert(
+ service.events.includes("testing"),
+ 'service.events is set and includes "testing"',
+ );
+ });
+
+ describe("Raw Methods", () => {
+ test("._get", () => {
+ assertStrictEquals(typeof service._get, "function");
+ });
+
+ test("._find", () => {
+ assertStrictEquals(typeof service._find, "function");
+ });
+
+ test("._create", () => {
+ assertStrictEquals(typeof service._create, "function");
+ });
+
+ test("._update", () => {
+ assertStrictEquals(typeof service._update, "function");
+ });
+
+ test("._patch", () => {
+ assertStrictEquals(typeof service._patch, "function");
+ });
+
+ test("._remove", () => {
+ assertStrictEquals(typeof service._remove, "function");
+ });
+
+ test(".$get", () => {
+ assertStrictEquals(typeof service.$get, "function");
+ });
+
+ test(".$find", () => {
+ assertStrictEquals(typeof service.$find, "function");
+ });
+
+ test(".$create", () => {
+ assertStrictEquals(typeof service.$create, "function");
+ });
+
+ test(".$update", () => {
+ assertStrictEquals(typeof service.$update, "function");
+ });
+
+ test(".$patch", () => {
+ assertStrictEquals(typeof service.$patch, "function");
+ });
+
+ test(".$remove", () => {
+ assertStrictEquals(typeof service.$remove, "function");
+ });
+ });
+ });
+};
diff --git a/main/adapter-tests/src/declarations.ts b/main/adapter-tests/src/declarations.ts
new file mode 100644
index 0000000000..5df8149496
--- /dev/null
+++ b/main/adapter-tests/src/declarations.ts
@@ -0,0 +1,102 @@
+export type AdapterTest = (name: AdapterTestName, runner: any) => void;
+
+export type AdapterBasicTest = (
+ name: AdapterBasicTestName,
+ runner: any,
+) => void;
+export type AdapterMethodsTest = (
+ name: AdapterMethodsTestName,
+ runner: any,
+) => void;
+export type AdapterSyntaxTest = (
+ name: AdapterSyntaxTestName,
+ runner: any,
+) => void;
+
+export type AdapterTestName =
+ | AdapterBasicTestName
+ | AdapterMethodsTestName
+ | AdapterSyntaxTestName;
+
+export type AdapterBasicTestName =
+ | ".id"
+ | ".options"
+ | ".events"
+ | "._get"
+ | "._find"
+ | "._create"
+ | "._update"
+ | "._patch"
+ | "._remove"
+ | ".$get"
+ | ".$find"
+ | ".$create"
+ | ".$update"
+ | ".$patch"
+ | ".$remove";
+
+export type AdapterMethodsTestName =
+ | ".get"
+ | ".get + $select"
+ | ".get + id + query"
+ | ".get + NotFound"
+ | ".get + id + query id"
+ | ".find"
+ | ".remove"
+ | ".remove + $select"
+ | ".remove + id + query"
+ | ".remove + multi"
+ | ".remove + multi no pagination"
+ | ".remove + id + query id"
+ | ".update"
+ | ".update + $select"
+ | ".update + id + query"
+ | ".update + NotFound"
+ | ".update + query + NotFound"
+ | ".update + id + query id"
+ | ".patch"
+ | ".patch + $select"
+ | ".patch + id + query"
+ | ".patch multiple"
+ | ".patch multiple no pagination"
+ | ".patch multi query same"
+ | ".patch multi query changed"
+ | ".patch + NotFound"
+ | ".patch + query + NotFound"
+ | ".patch + id + query id"
+ | ".create"
+ | ".create + $select"
+ | ".create multi"
+ | "internal .find"
+ | "internal .get"
+ | "internal .create"
+ | "internal .update"
+ | "internal .patch"
+ | "internal .remove";
+
+export type AdapterSyntaxTestName =
+ | ".find + equal"
+ | ".find + equal multiple"
+ | ".find + $sort"
+ | ".find + $sort + string"
+ | ".find + $limit"
+ | ".find + $limit 0"
+ | ".find + $skip"
+ | ".find + $select"
+ | ".find + $or"
+ | ".find + $in"
+ | ".find + $nin"
+ | ".find + $lt"
+ | ".find + $lte"
+ | ".find + $gt"
+ | ".find + $gte"
+ | ".find + $ne"
+ | ".find + $gt + $lt + $sort"
+ | ".find + $or nested + $sort"
+ | "params.adapter + paginate"
+ | "params.adapter + multi"
+ | ".find + paginate"
+ | ".find + paginate + query"
+ | ".find + paginate + $limit + $skip"
+ | ".find + paginate + $limit 0"
+ | ".find + paginate + params";
diff --git a/main/adapter-tests/src/index.ts b/main/adapter-tests/src/index.ts
new file mode 100644
index 0000000000..a379abb27f
--- /dev/null
+++ b/main/adapter-tests/src/index.ts
@@ -0,0 +1,59 @@
+import basicTests from "./basic.ts";
+import { AdapterTestName } from "./declarations.ts";
+import methodTests from "./methods.ts";
+import syntaxTests from "./syntax.ts";
+import { afterAll, describe, it } from "../../commons/mod.ts";
+
+const adapterTests = (testNames: AdapterTestName[]) => {
+ return (app: any, errors: any, serviceName: any, idProp = "id") => {
+ if (!serviceName) {
+ throw new Error("You must pass a service name");
+ }
+
+ const skippedTests: AdapterTestName[] = [];
+ const allTests: AdapterTestName[] = [];
+
+ const test = (name: AdapterTestName, runner: any) => {
+ const skip = !testNames.includes(name);
+ const its = skip ? it.ignore : it;
+
+ if (skip) {
+ skippedTests.push(name);
+ }
+
+ allTests.push(name);
+
+ its(name, runner);
+ };
+
+ describe(`Adapter tests for '${serviceName}' service with '${idProp}' id property`, () => {
+ afterAll(() => {
+ testNames.forEach((name) => {
+ if (!allTests.includes(name)) {
+ console.error(
+ `WARNING: '${name}' test is not part of the test suite`,
+ );
+ }
+ });
+ if (skippedTests.length) {
+ console.log(
+ `\nSkipped the following ${skippedTests.length} Feathers adapter test(s) out of ${allTests.length} total:`,
+ );
+ console.log(JSON.stringify(skippedTests, null, " "));
+ }
+ });
+
+ basicTests(test, app, errors, serviceName, idProp);
+ methodTests(test, app, errors, serviceName, idProp);
+ syntaxTests(test, app, errors, serviceName, idProp);
+ });
+ };
+};
+
+export * from "./declarations.ts";
+
+export default adapterTests;
+
+// if (typeof module !== 'undefined') {
+// module.exports = Object.assign(adapterTests, module.exports)
+// }
diff --git a/main/adapter-tests/src/methods.ts b/main/adapter-tests/src/methods.ts
new file mode 100644
index 0000000000..0b96ad9475
--- /dev/null
+++ b/main/adapter-tests/src/methods.ts
@@ -0,0 +1,844 @@
+import {
+ afterEach,
+ assert,
+ assertEquals,
+ assertStrictEquals,
+ beforeAll,
+ beforeEach,
+ describe,
+} from "../../commons/mod.ts";
+import { AdapterMethodsTest } from "./declarations.ts";
+
+export default (
+ test: AdapterMethodsTest,
+ app: any,
+ _errors: any,
+ serviceName: string,
+ idProp: string,
+) => {
+ describe(" Methods", () => {
+ let doug: any;
+ let service: any;
+
+ beforeEach(async () => {
+ service = app.service(serviceName);
+ doug = await app.service(serviceName).create({
+ name: "Doug",
+ age: 32,
+ });
+ });
+
+ afterEach(async () => {
+ try {
+ await app.service(serviceName).remove(doug[idProp]);
+ } catch (error: any) {}
+ });
+
+ describe("get", () => {
+ test(".get", async () => {
+ const data = await service.get(doug[idProp]);
+
+ assertStrictEquals(
+ data[idProp].toString(),
+ doug[idProp].toString(),
+ `${idProp} id matches`,
+ );
+ assertStrictEquals(data.name, "Doug", "data.name matches");
+ assertStrictEquals(data.age, 32, "data.age matches");
+ });
+
+ test(".get + $select", async () => {
+ const data = await service.get(doug[idProp], {
+ query: { $select: ["name"] },
+ });
+
+ assertStrictEquals(
+ data[idProp].toString(),
+ doug[idProp].toString(),
+ `${idProp} id property matches`,
+ );
+ assertStrictEquals(data.name, "Doug", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+ });
+
+ test(".get + id + query", async () => {
+ try {
+ await service.get(doug[idProp], {
+ query: { name: "Tester" },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".get + NotFound", async () => {
+ try {
+ await service.get("568225fbfe21222432e836ff");
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Error is a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".get + id + query id", async () => {
+ const alice = await service.create({
+ name: "Alice",
+ age: 12,
+ });
+
+ try {
+ await service.get(doug[idProp], {
+ query: { [idProp]: alice[idProp] },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+
+ await service.remove(alice[idProp]);
+ });
+ });
+
+ describe("find", () => {
+ test(".find", async () => {
+ const data = await service.find();
+
+ assert(Array.isArray(data), "Data is an array");
+ assertStrictEquals(data.length, 1, "Got one entry");
+ });
+ });
+
+ describe("remove", () => {
+ test(".remove", async () => {
+ const data = await service.remove(doug[idProp]);
+
+ assertStrictEquals(data.name, "Doug", "data.name matches");
+ });
+
+ test(".remove + $select", async () => {
+ const data = await service.remove(doug[idProp], {
+ query: { $select: ["name"] },
+ });
+
+ assertStrictEquals(data.name, "Doug", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+ });
+
+ test(".remove + id + query", async () => {
+ try {
+ await service.remove(doug[idProp], {
+ query: { name: "Tester" },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".remove + multi", async () => {
+ try {
+ await service.remove(null);
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "MethodNotAllowed",
+ "Removing multiple without option set throws MethodNotAllowed",
+ );
+ }
+
+ service.options.multi = ["remove"];
+
+ await service.create({ name: "Dave", age: 29, created: true });
+ await service.create({
+ name: "David",
+ age: 3,
+ created: true,
+ });
+
+ const data = await service.remove(null, {
+ query: { created: true },
+ });
+
+ assertStrictEquals(data.length, 2);
+
+ const names = data.map((person: any) => person.name);
+
+ assert(names.includes("Dave"), "Dave removed");
+ assert(names.includes("David"), "David removed");
+ });
+
+ test(".remove + multi no pagination", async () => {
+ try {
+ await service.remove(doug[idProp]);
+ } catch (error: any) {}
+
+ const count = 14;
+ const defaultPaginate = 10;
+
+ assert(
+ count > defaultPaginate,
+ "count is bigger than default pagination",
+ );
+
+ const multiBefore = service.options.multi;
+ const paginateBefore = service.options.paginate;
+
+ try {
+ service.options.multi = true;
+ service.options.paginate = {
+ default: defaultPaginate,
+ max: 100,
+ };
+
+ const emptyItems = await service.find({ paginate: false });
+ assertStrictEquals(emptyItems.length, 0, "no items before");
+
+ const createdItems = await service.create(
+ Array.from(Array(count)).map((_, i) => ({
+ name: `name-${i}`,
+ age: 3,
+ created: true,
+ })),
+ );
+ assertStrictEquals(
+ createdItems.length,
+ count,
+ `created ${count} items`,
+ );
+
+ const foundItems = await service.find({ paginate: false });
+ assertStrictEquals(
+ foundItems.length,
+ count,
+ `created ${count} items`,
+ );
+
+ const foundPaginatedItems = await service.find({});
+ assertStrictEquals(
+ foundPaginatedItems.data.length,
+ defaultPaginate,
+ "found paginated items",
+ );
+
+ const allItems = await service.remove(null, {
+ query: { created: true },
+ });
+
+ assertStrictEquals(
+ allItems.length,
+ count,
+ `removed all ${count} items`,
+ );
+ } finally {
+ await service.remove(null, {
+ query: { created: true },
+ paginate: false,
+ });
+
+ service.options.multi = multiBefore;
+ service.options.paginate = paginateBefore;
+ }
+ });
+
+ test(".remove + id + query id", async () => {
+ const alice = await service.create({
+ name: "Alice",
+ age: 12,
+ });
+
+ try {
+ await service.remove(doug[idProp], {
+ query: { [idProp]: alice[idProp] },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+
+ await service.remove(alice[idProp]);
+ });
+ });
+
+ describe("update", () => {
+ test(".update", async () => {
+ const originalData = { [idProp]: doug[idProp], name: "Dougler" };
+ const originalCopy = Object.assign({}, originalData);
+
+ const data = await service.update(doug[idProp], originalData);
+
+ assertEquals(
+ originalData,
+ originalCopy,
+ "data was not modified",
+ );
+ assertStrictEquals(
+ data[idProp].toString(),
+ doug[idProp].toString(),
+ `${idProp} id matches`,
+ );
+ assertStrictEquals(data.name, "Dougler", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+ });
+
+ test(".update + $select", async () => {
+ const originalData = {
+ [idProp]: doug[idProp],
+ name: "Dougler",
+ age: 10,
+ };
+
+ const data = await service.update(doug[idProp], originalData, {
+ query: { $select: ["name"] },
+ });
+
+ assertStrictEquals(data.name, "Dougler", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+ });
+
+ test(".update + id + query", async () => {
+ try {
+ await service.update(
+ doug[idProp],
+ {
+ name: "Dougler",
+ },
+ {
+ query: { name: "Tester" },
+ },
+ );
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".update + NotFound", async () => {
+ try {
+ await service.update("568225fbfe21222432e836ff", {
+ name: "NotFound",
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Error is a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".update + query + NotFound", async () => {
+ const dave = await service.create({ name: "Dave" });
+ try {
+ await service.update(dave[idProp], { name: "UpdatedDave" }, {
+ query: { name: "NotDave" },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Error is a NotFound Feathers error",
+ );
+ }
+ await service.remove(dave[idProp]);
+ });
+
+ test(".update + id + query id", async () => {
+ const alice = await service.create({
+ name: "Alice",
+ age: 12,
+ });
+
+ try {
+ await service.update(
+ doug[idProp],
+ {
+ name: "Dougler",
+ age: 33,
+ },
+ {
+ query: { [idProp]: alice[idProp] },
+ },
+ );
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+
+ await service.remove(alice[idProp]);
+ });
+ });
+
+ describe("patch", () => {
+ test(".patch", async () => {
+ const originalData = { [idProp]: doug[idProp], name: "PatchDoug" };
+ const originalCopy = Object.assign({}, originalData);
+
+ const data = await service.patch(doug[idProp], originalData);
+
+ assertEquals(
+ originalData,
+ originalCopy,
+ "original data was not modified",
+ );
+ assertStrictEquals(
+ data[idProp].toString(),
+ doug[idProp].toString(),
+ `${idProp} id matches`,
+ );
+ assertStrictEquals(data.name, "PatchDoug", "data.name matches");
+ assertStrictEquals(data.age, 32, "data.age matches");
+ });
+
+ test(".patch + $select", async () => {
+ const originalData = { [idProp]: doug[idProp], name: "PatchDoug" };
+
+ const data = await service.patch(doug[idProp], originalData, {
+ query: { $select: ["name"] },
+ });
+
+ assertStrictEquals(data.name, "PatchDoug", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+ });
+
+ test(".patch + id + query", async () => {
+ try {
+ await service.patch(
+ doug[idProp],
+ {
+ name: "id patched doug",
+ },
+ {
+ query: { name: "Tester" },
+ },
+ );
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".patch multiple", async () => {
+ try {
+ await service.patch(null, {});
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "MethodNotAllowed",
+ "Removing multiple without option set throws MethodNotAllowed",
+ );
+ }
+
+ const params = {
+ query: { created: true },
+ };
+ const dave = await service.create({
+ name: "Dave",
+ age: 29,
+ created: true,
+ });
+ const david = await service.create({
+ name: "David",
+ age: 3,
+ created: true,
+ });
+
+ service.options.multi = ["patch"];
+
+ const data = await service.patch(
+ null,
+ {
+ age: 2,
+ },
+ params,
+ );
+
+ assertStrictEquals(data.length, 2, "returned two entries");
+ assertStrictEquals(data[0].age, 2, "First entry age was updated");
+ assertStrictEquals(data[1].age, 2, "Second entry age was updated");
+
+ await service.remove(dave[idProp]);
+ await service.remove(david[idProp]);
+ });
+
+ test(".patch multiple no pagination", async () => {
+ try {
+ await service.remove(doug[idProp]);
+ } catch (error: any) {}
+
+ const count = 14;
+ const defaultPaginate = 10;
+
+ assert(
+ count > defaultPaginate,
+ "count is bigger than default pagination",
+ );
+
+ const multiBefore = service.options.multi;
+ const paginateBefore = service.options.paginate;
+
+ let ids: any[];
+
+ try {
+ service.options.multi = true;
+ service.options.paginate = {
+ default: defaultPaginate,
+ max: 100,
+ };
+
+ const emptyItems = await service.find({ paginate: false });
+ assertStrictEquals(emptyItems.length, 0, "no items before");
+
+ const createdItems = await service.create(
+ Array.from(Array(count)).map((_, i) => ({
+ name: `name-${i}`,
+ age: 3,
+ created: true,
+ })),
+ );
+ assertStrictEquals(
+ createdItems.length,
+ count,
+ `created ${count} items`,
+ );
+ ids = createdItems.map((item: any) => item[idProp]);
+
+ const foundItems = await service.find({ paginate: false });
+ assertStrictEquals(
+ foundItems.length,
+ count,
+ `created ${count} items`,
+ );
+
+ const foundPaginatedItems = await service.find({});
+ assertStrictEquals(
+ foundPaginatedItems.data.length,
+ defaultPaginate,
+ "found paginated data",
+ );
+
+ const allItems = await service.patch(null, { age: 4 }, {
+ query: { created: true },
+ });
+
+ assertStrictEquals(
+ allItems.length,
+ count,
+ `patched all ${count} items`,
+ );
+ } finally {
+ service.options.multi = multiBefore;
+ service.options.paginate = paginateBefore;
+ if (ids!) {
+ await Promise.all(ids.map((id) => service.remove(id)));
+ }
+ }
+ });
+
+ test(".patch multi query same", async () => {
+ const service = app.service(serviceName);
+ const multiBefore = service.options.multi;
+
+ service.options.multi = true;
+
+ const params = {
+ query: { age: { $lt: 10 } },
+ };
+ const dave = await service.create({
+ name: "Dave",
+ age: 8,
+ created: true,
+ });
+ const david = await service.create({
+ name: "David",
+ age: 4,
+ created: true,
+ });
+
+ const data = await service.patch(
+ null,
+ {
+ age: 2,
+ },
+ params,
+ );
+
+ assertStrictEquals(data.length, 2, "returned two entries");
+ assertStrictEquals(data[0].age, 2, "First entry age was updated");
+ assertStrictEquals(data[1].age, 2, "Second entry age was updated");
+
+ await service.remove(dave[idProp]);
+ await service.remove(david[idProp]);
+
+ service.options.multi = multiBefore;
+ });
+
+ test(".patch multi query changed", async () => {
+ const service = app.service(serviceName);
+ const multiBefore = service.options.multi;
+
+ service.options.multi = true;
+
+ const params = {
+ query: { age: 10 },
+ };
+ const dave = await service.create({
+ name: "Dave",
+ age: 10,
+ created: true,
+ });
+ const david = await service.create({
+ name: "David",
+ age: 10,
+ created: true,
+ });
+
+ const data = await service.patch(
+ null,
+ {
+ age: 2,
+ },
+ params,
+ );
+
+ assertStrictEquals(data.length, 2, "returned two entries");
+ assertStrictEquals(data[0].age, 2, "First entry age was updated");
+ assertStrictEquals(data[1].age, 2, "Second entry age was updated");
+
+ await service.remove(dave[idProp]);
+ await service.remove(david[idProp]);
+
+ service.options.multi = multiBefore;
+ });
+
+ test(".patch + NotFound", async () => {
+ try {
+ await service.patch("568225fbfe21222432e836ff", {
+ name: "PatchDoug",
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Error is a NotFound Feathers error",
+ );
+ }
+ });
+
+ test(".patch + query + NotFound", async () => {
+ const dave = await service.create({ name: "Dave" });
+ try {
+ await service.patch(dave[idProp], { name: "PatchedDave" }, {
+ query: { name: "NotDave" },
+ });
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Error is a NotFound Feathers error",
+ );
+ }
+ await service.remove(dave[idProp]);
+ });
+
+ test(".patch + id + query id", async () => {
+ const alice = await service.create({
+ name: "Alice",
+ age: 12,
+ });
+
+ try {
+ await service.patch(
+ doug[idProp],
+ {
+ age: 33,
+ },
+ {
+ query: { [idProp]: alice[idProp] },
+ },
+ );
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "NotFound",
+ "Got a NotFound Feathers error",
+ );
+ }
+
+ await service.remove(alice[idProp]);
+ });
+ });
+
+ describe("create", () => {
+ test(".create", async () => {
+ const originalData = {
+ name: "Bill",
+ age: 40,
+ };
+ const originalCopy = Object.assign({}, originalData);
+
+ const data = await service.create(originalData);
+
+ assertEquals(
+ originalData,
+ originalCopy,
+ "original data was not modified",
+ );
+ assert(data instanceof Object, "data is an object");
+ assertStrictEquals(data.name, "Bill", "data.name matches");
+
+ await service.remove(data[idProp]);
+ });
+
+ test(".create + $select", async () => {
+ const originalData = {
+ name: "William",
+ age: 23,
+ };
+
+ const data = await service.create(originalData, {
+ query: { $select: ["name"] },
+ });
+
+ assertStrictEquals(data.name, "William", "data.name matches");
+ assert(!data.age, "data.age is falsy");
+
+ await service.remove(data[idProp]);
+ });
+
+ test(".create multi", async () => {
+ try {
+ await service.create([], {});
+ throw new Error("Should never get here");
+ } catch (error: any) {
+ assertStrictEquals(
+ error.name,
+ "MethodNotAllowed",
+ "Removing multiple without option set throws MethodNotAllowed",
+ );
+ }
+
+ const items = [
+ {
+ name: "Gerald",
+ age: 18,
+ },
+ {
+ name: "Herald",
+ age: 18,
+ },
+ ];
+
+ service.options.multi = ["create", "patch"];
+
+ const data = await service.create(items);
+
+ assert(Array.isArray(data), "data is an array");
+ assert(typeof data[0][idProp] !== "undefined", "id is set");
+ assertStrictEquals(data[0].name, "Gerald", "first name matches");
+ assert(typeof data[1][idProp] !== "undefined", "id is set");
+ assertStrictEquals(data[1].name, "Herald", "second name macthes");
+
+ await service.remove(data[0][idProp]);
+ await service.remove(data[1][idProp]);
+ });
+ });
+
+ describe("doesn't call public methods internally", () => {
+ let throwing: any;
+
+ beforeAll(() => {
+ throwing = Object.assign(Object.create(app.service(serviceName)), {
+ get store() {
+ return app.service(serviceName).store;
+ },
+
+ find() {
+ throw new Error("find method called");
+ },
+ get() {
+ throw new Error("get method called");
+ },
+ create() {
+ throw new Error("create method called");
+ },
+ update() {
+ throw new Error("update method called");
+ },
+ patch() {
+ throw new Error("patch method called");
+ },
+ remove() {
+ throw new Error("remove method called");
+ },
+ });
+ });
+
+ test("internal .find", () =>
+ app.service(serviceName).find.call(throwing));
+
+ test("internal .get", () => service.get.call(throwing, doug[idProp]));
+
+ test("internal .create", async () => {
+ const bob = await service.create.call(throwing, {
+ name: "Bob",
+ age: 25,
+ });
+
+ await service.remove(bob[idProp]);
+ });
+
+ test("internal .update", () =>
+ service.update.call(throwing, doug[idProp], {
+ name: "Dougler",
+ }));
+
+ test("internal .patch", () =>
+ service.patch.call(throwing, doug[idProp], {
+ name: "PatchDoug",
+ }));
+
+ test("internal .remove", () =>
+ service.remove.call(throwing, doug[idProp]));
+ });
+ });
+};
diff --git a/main/adapter-tests/src/syntax.ts b/main/adapter-tests/src/syntax.ts
new file mode 100644
index 0000000000..1a82e73c2f
--- /dev/null
+++ b/main/adapter-tests/src/syntax.ts
@@ -0,0 +1,408 @@
+import {
+ afterEach,
+ assert,
+ assertEquals,
+ assertRejects,
+ assertStrictEquals,
+ beforeEach,
+ describe,
+} from "../../commons/mod.ts";
+import { AdapterSyntaxTest } from "./declarations.ts";
+
+export default (
+ test: AdapterSyntaxTest,
+ app: any,
+ _errors: any,
+ serviceName: string,
+ idProp: string,
+) => {
+ describe("Query Syntax", () => {
+ let bob: any;
+ let alice: any;
+ let doug: any;
+ let service: any;
+
+ beforeEach(async () => {
+ service = app.service(serviceName);
+ bob = await app.service(serviceName).create({
+ name: "Bob",
+ age: 25,
+ });
+ doug = await app.service(serviceName).create({
+ name: "Doug",
+ age: 32,
+ });
+ alice = await app.service(serviceName).create({
+ name: "Alice",
+ age: 19,
+ });
+ });
+
+ afterEach(async () => {
+ await service.remove(bob[idProp]);
+ await service.remove(alice[idProp]);
+ await service.remove(doug[idProp]);
+ });
+
+ test(".find + equal", async () => {
+ const params = { query: { name: "Alice" } };
+ const data = await service.find(params);
+
+ assert(Array.isArray(data));
+ assertStrictEquals(data.length, 1);
+ assertStrictEquals(data[0].name, "Alice");
+ });
+
+ test(".find + equal multiple", async () => {
+ const data = await service.find({
+ query: { name: "Alice", age: 20 },
+ });
+
+ assertStrictEquals(data.length, 0);
+ });
+
+ describe("special filters", () => {
+ test(".find + $sort", async () => {
+ let data = await service.find({
+ query: {
+ $sort: { name: 1 },
+ },
+ });
+
+ assertStrictEquals(data.length, 3);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Bob");
+ assertStrictEquals(data[2].name, "Doug");
+
+ data = await service.find({
+ query: {
+ $sort: { name: -1 },
+ },
+ });
+
+ assertStrictEquals(data.length, 3);
+ assertStrictEquals(data[0].name, "Doug");
+ assertStrictEquals(data[1].name, "Bob");
+ assertStrictEquals(data[2].name, "Alice");
+ });
+
+ test(".find + $sort + string", async () => {
+ const data = await service.find({
+ query: {
+ $sort: { name: "1" },
+ },
+ });
+
+ assertStrictEquals(data.length, 3);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Bob");
+ assertStrictEquals(data[2].name, "Doug");
+ });
+
+ test(".find + $limit", async () => {
+ const data = await service.find({
+ query: {
+ $limit: 2,
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ });
+
+ test(".find + $limit 0", async () => {
+ const data = await service.find({
+ query: {
+ $limit: 0,
+ },
+ });
+
+ assertStrictEquals(data.length, 0);
+ });
+
+ test(".find + $skip", async () => {
+ const data = await service.find({
+ query: {
+ $sort: { name: 1 },
+ $skip: 1,
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ assertStrictEquals(data[0].name, "Bob");
+ assertStrictEquals(data[1].name, "Doug");
+ });
+
+ test(".find + $select", async () => {
+ const data = await service.find({
+ query: {
+ name: "Alice",
+ $select: ["name"],
+ },
+ });
+
+ assertStrictEquals(data.length, 1);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[0].age, undefined);
+ });
+
+ test(".find + $or", async () => {
+ const data = await service.find({
+ query: {
+ $or: [{ name: "Alice" }, { name: "Bob" }],
+ $sort: { name: 1 },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Bob");
+ });
+
+ test(".find + $in", async () => {
+ const data = await service.find({
+ query: {
+ name: {
+ $in: ["Alice", "Bob"],
+ },
+ $sort: { name: 1 },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Bob");
+ });
+
+ test(".find + $nin", async () => {
+ const data = await service.find({
+ query: {
+ name: {
+ $nin: ["Alice", "Bob"],
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 1);
+ assertStrictEquals(data[0].name, "Doug");
+ });
+
+ test(".find + $lt", async () => {
+ const data = await service.find({
+ query: {
+ age: {
+ $lt: 30,
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ });
+
+ test(".find + $lte", async () => {
+ const data = await service.find({
+ query: {
+ age: {
+ $lte: 25,
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ });
+
+ test(".find + $gt", async () => {
+ const data = await service.find({
+ query: {
+ age: {
+ $gt: 30,
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 1);
+ });
+
+ test(".find + $gte", async () => {
+ const data = await service.find({
+ query: {
+ age: {
+ $gte: 25,
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ });
+
+ test(".find + $ne", async () => {
+ const data = await service.find({
+ query: {
+ age: {
+ $ne: 25,
+ },
+ },
+ });
+
+ assertStrictEquals(data.length, 2);
+ });
+ });
+
+ test(".find + $gt + $lt + $sort", async () => {
+ const params = {
+ query: {
+ age: {
+ $gt: 18,
+ $lt: 30,
+ },
+ $sort: { name: 1 },
+ },
+ };
+
+ const data = await service.find(params);
+
+ assertStrictEquals(data.length, 2);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Bob");
+ });
+
+ test(".find + $or nested + $sort", async () => {
+ const params = {
+ query: {
+ $or: [
+ { name: "Doug" },
+ {
+ age: {
+ $gte: 18,
+ $lt: 25,
+ },
+ },
+ ],
+ $sort: { name: 1 },
+ },
+ };
+
+ const data = await service.find(params);
+
+ assertStrictEquals(data.length, 2);
+ assertStrictEquals(data[0].name, "Alice");
+ assertStrictEquals(data[1].name, "Doug");
+ });
+
+ describe("params.adapter", () => {
+ test("params.adapter + paginate", async () => {
+ const page = await service.find({
+ adapter: {
+ paginate: { default: 3 },
+ },
+ });
+
+ assertStrictEquals(page.limit, 3);
+ assertStrictEquals(page.skip, 0);
+ });
+
+ test("params.adapter + multi", async () => {
+ const items = [
+ {
+ name: "Garald",
+ age: 200,
+ },
+ {
+ name: "Harald",
+ age: 24,
+ },
+ ];
+ const multiParams = {
+ adapter: {
+ multi: ["create"],
+ },
+ };
+ const users = await service.create(items, multiParams);
+
+ assertStrictEquals(users.length, 2);
+
+ await service.remove(users[0][idProp]);
+ await service.remove(users[1][idProp]);
+ await assertRejects(
+ () => service.patch(null, { age: 2 }, multiParams),"Can not patch multiple entries",
+ );
+ });
+ });
+
+ describe("paginate", function () {
+ beforeEach(() => {
+ service.options.paginate = {
+ default: 1,
+ max: 2,
+ };
+ });
+
+ afterEach(() => {
+ service.options.paginate = {};
+ });
+
+ test(".find + paginate", async () => {
+ const page = await service.find({
+ query: { $sort: { name: -1 } },
+ });
+
+ assertStrictEquals(page.total, 3);
+ assertStrictEquals(page.limit, 1);
+ assertStrictEquals(page.skip, 0);
+ assertStrictEquals(page.data[0].name, "Doug");
+ });
+
+ test(".find + paginate + query", async () => {
+ const page = await service.find({
+ query: {
+ $sort: { name: -1 },
+ name: "Doug",
+ },
+ });
+
+ assertStrictEquals(page.total, 1);
+ assertStrictEquals(page.limit, 1);
+ assertStrictEquals(page.skip, 0);
+ assertStrictEquals(page.data[0].name, "Doug");
+ });
+
+ test(".find + paginate + $limit + $skip", async () => {
+ const params = {
+ query: {
+ $skip: 1,
+ $limit: 4,
+ $sort: { name: -1 },
+ },
+ };
+
+ const page = await service.find(params);
+
+ assertStrictEquals(page.total, 3);
+ assertStrictEquals(page.limit, 2);
+ assertStrictEquals(page.skip, 1);
+ assertStrictEquals(page.data[0].name, "Bob");
+ assertStrictEquals(page.data[1].name, "Alice");
+ });
+
+ test(".find + paginate + $limit 0", async () => {
+ const page = await service.find({
+ query: { $limit: 0 },
+ });
+
+ assertStrictEquals(page.total, 3);
+ assertStrictEquals(page.data.length, 0);
+ });
+
+ test(".find + paginate + params", async () => {
+ const page = await service.find({ paginate: { default: 3 } });
+
+ assertStrictEquals(page.limit, 3);
+ assertStrictEquals(page.skip, 0);
+
+ const results = await service.find({ paginate: false });
+
+ assert(Array.isArray(results));
+ assertStrictEquals(results.length, 3);
+ });
+ });
+ });
+};
diff --git a/main/adapter-tests/test/index.test.ts b/main/adapter-tests/test/index.test.ts
new file mode 100644
index 0000000000..f7faab8fb0
--- /dev/null
+++ b/main/adapter-tests/test/index.test.ts
@@ -0,0 +1,85 @@
+import { assert, describe, it } from "../../commons/mod.ts";
+import adapterTests from "../mod.ts";
+
+const testSuite = adapterTests([
+ ".events",
+ "._get",
+ "._find",
+ "._create",
+ "._update",
+ "._patch",
+ "._remove",
+ ".$get",
+ ".$find",
+ ".$create",
+ ".$update",
+ ".$patch",
+ ".$remove",
+ ".get",
+ ".get + $select",
+ ".get + id + query",
+ ".get + NotFound",
+ ".find",
+ ".remove",
+ ".remove + $select",
+ ".remove + id + query",
+ ".remove + multi",
+ ".remove + multi no pagination",
+ ".update",
+ ".update + $select",
+ ".update + id + query",
+ ".update + NotFound",
+ ".patch",
+ ".patch + $select",
+ ".patch + id + query",
+ ".patch multiple",
+ ".patch multiple no pagination",
+ ".patch multi query changed",
+ ".patch multi query same",
+ ".patch + NotFound",
+ ".create",
+ ".create + $select",
+ ".create multi",
+ "internal .find",
+ "internal .get",
+ "internal .create",
+ "internal .update",
+ "internal .patch",
+ "internal .remove",
+ ".find + equal",
+ ".find + equal multiple",
+ ".find + $sort",
+ ".find + $sort + string",
+ ".find + $limit",
+ ".find + $limit 0",
+ ".find + $skip",
+ ".find + $select",
+ ".find + $or",
+ ".find + $in",
+ ".find + $nin",
+ ".find + $lt",
+ ".find + $lte",
+ ".find + $gt",
+ ".find + $gte",
+ ".find + $ne",
+ ".find + $gt + $lt + $sort",
+ ".find + $or nested + $sort",
+ ".find + paginate",
+ ".find + paginate + $limit + $skip",
+ ".find + paginate + $limit 0",
+ ".find + paginate + params",
+ ".get + id + query id",
+ ".remove + id + query id",
+ ".update + id + query id",
+ ".patch + id + query id",
+]);
+
+describe("Feathers Memory Service", () => {
+ it("loads the test suite", () => {
+ assert(typeof testSuite === "function");
+ });
+
+ it.ignore("exports as CommonJS", () => {
+ // assert.equal(typeof require("../lib"), "function");
+ });
+});
diff --git a/main/commons/LICENSE b/main/commons/LICENSE
index 3f395cc665..59604f46f3 100644
--- a/main/commons/LICENSE
+++ b/main/commons/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2021 Feathers
+Copyright (c) 2022 Feathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/main/commons/mod.ts b/main/commons/mod.ts
new file mode 100644
index 0000000000..3b3419b271
--- /dev/null
+++ b/main/commons/mod.ts
@@ -0,0 +1 @@
+export * from "./src/index.ts";
diff --git a/main/commons/src/events.ts b/main/commons/src/events.js
similarity index 50%
rename from main/commons/src/events.ts
rename to main/commons/src/events.js
index 96090a2b47..febb8e88ac 100644
--- a/main/commons/src/events.ts
+++ b/main/commons/src/events.js
@@ -1,101 +1,89 @@
-/* eslint-disable no-console */
-// deno-lint-ignore-file no-explicit-any
-// deno-lint-ignore-file no-implicit-any
-
-// Adapted from node_modules/events/events.js for Deno
-
-// Copyright Joyent, Inc. and other Node contributors.
+/* eslint-disable no-console */
+// deno-lint-ignore-file no-explicit-any
+// deno-lint-ignore-file no-implicit-any
+// Adapted from node_modules/events/events.js for Deno
+// Copyright Joyent, Inc. and other Node contributors.
//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-const R = typeof Reflect === 'object' ? Reflect : null;
-const ReflectApply = R && typeof R.apply === 'function'
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+const R = typeof Reflect === "object" ? Reflect : null;
+const ReflectApply = R && typeof R.apply === "function"
? R.apply
- : function ReflectApply (target: any, receiver: any, args: any) {
+ : function ReflectApply(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
};
-
-let ReflectOwnKeys: any;
-if (R && typeof R.ownKeys === 'function') {
+let ReflectOwnKeys;
+if (R && typeof R.ownKeys === "function") {
ReflectOwnKeys = R.ownKeys;
} else if (Object.getOwnPropertySymbols) {
- ReflectOwnKeys = function ReflectOwnKeys (target: any) {
- return Object.getOwnPropertyNames(target)
- // @ts-ignore suppress
+ ReflectOwnKeys = function ReflectOwnKeys(target) {
+ return Object.getOwnPropertyNames(target) // @ts-ignore suppress
.concat(Object.getOwnPropertySymbols(target));
};
} else {
- ReflectOwnKeys = function ReflectOwnKeys (target: any) {
+ ReflectOwnKeys = function ReflectOwnKeys(target) {
return Object.getOwnPropertyNames(target);
};
}
-
-function ProcessEmitWarning (warning: any) {
+function ProcessEmitWarning(warning) {
if (console && console.warn) console.warn(warning);
}
-
-const NumberIsNaN = Number.isNaN || function NumberIsNaN (value) {
- return value !== value;
-};
-
-function EventEmitter (this: any) {
+const NumberIsNaN = Number.isNaN ||
+ function NumberIsNaN(value) {
+ return value !== value;
+ };
+function EventEmitter() {
EventEmitter.init.call(this);
}
-
-// Backwards-compat with node 0.10.x
+// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
-
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0;
EventEmitter.prototype._maxListeners = undefined;
-
-// By default EventEmitters will print a warning if more than 10 listeners are
-// added to it. This is a useful default which helps finding memory leaks.
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
let defaultMaxListeners = 10;
-
-function checkListener (listener: any) {
- if (typeof listener !== 'function') {
+function checkListener(listener) {
+ if (typeof listener !== "function") {
throw new TypeError(
- 'The "listener" argument must be of type Function. Received type ' +
- typeof listener
+ 'The "listener" argument must be of type Function. Received type ' +
+ typeof listener,
);
}
}
-
-Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
+Object.defineProperty(EventEmitter, "defaultMaxListeners", {
enumerable: true,
- get () {
+ get() {
return defaultMaxListeners;
},
- set (arg) {
- if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
+ set(arg) {
+ if (typeof arg !== "number" || arg < 0 || NumberIsNaN(arg)) {
throw new RangeError(
- 'The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' +
- arg + '.'
+ 'The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' +
+ arg +
+ ".",
);
}
defaultMaxListeners = arg;
- }
+ },
});
-
-EventEmitter.init = function (this: { _events: any, _eventsCount: number, _maxListeners: number | undefined }) {
+EventEmitter.init = function () {
if (
this._events === undefined ||
this._events === Object.getPrototypeOf(this)._events
@@ -103,73 +91,62 @@ EventEmitter.init = function (this: { _events: any, _eventsCount: number, _maxLi
this._events = Object.create(null);
this._eventsCount = 0;
}
-
this._maxListeners = this._maxListeners || undefined;
};
-
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-EventEmitter.prototype.setMaxListeners = function setMaxListeners (n: number) {
- if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
+ if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) {
throw new RangeError(
- 'The value of "n" is out of range. It must be a non-negative number. Received ' +
- n + '.'
+ 'The value of "n" is out of range. It must be a non-negative number. Received ' +
+ n +
+ ".",
);
}
this._maxListeners = n;
return this;
};
-
-function _getMaxListeners (that: any) {
+function _getMaxListeners(that) {
if (that._maxListeners === undefined) {
- // @ts-ignore suppress
+ // @ts-ignore suppress
return EventEmitter.defaultMaxListeners;
}
return that._maxListeners;
}
-
-EventEmitter.prototype.getMaxListeners = function getMaxListeners () {
+EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return _getMaxListeners(this);
};
-
-EventEmitter.prototype.emit = function emit (type: any) {
+EventEmitter.prototype.emit = function emit(type) {
const args = [];
for (let i = 1; i < arguments.length; i++) args.push(arguments[i]);
- let doError = (type === 'error');
-
+ let doError = type === "error";
const events = this._events;
if (events !== undefined) {
doError = doError && events.error === undefined;
} else if (!doError) {
return false;
- }
-
- // If there is no 'error' event listener then throw.
+ } // If there is no 'error' event listener then throw.
if (doError) {
let er;
if (args.length > 0) {
er = args[0];
}
if (er instanceof Error) {
- // Note: The comments on the `throw` lines are intentional, they show
- // up in Node's output if this results in an unhandled exception.
- throw er; // Unhandled 'error' event
- }
- // At least give some kind of context to the user
- const err: any = new Error(
- 'Unhandled error.' + (er ? ' (' + er.message + ')' : '')
+ // Note: The comments on the `throw` lines are intentional, they show
+ // up in Node's output if this results in an unhandled exception.
+ throw er; // Unhandled 'error' event
+ } // At least give some kind of context to the user
+ const err = new Error(
+ "Unhandled error." + (er ? " (" + er.message + ")" : ""),
);
err.context = er;
- throw err; // Unhandled 'error' event
+ throw err; // Unhandled 'error' event
}
-
const handler = events[type];
-
if (handler === undefined) {
return false;
}
-
- if (typeof handler === 'function') {
+ if (typeof handler === "function") {
ReflectApply(handler, this, args);
} else {
const len = handler.length;
@@ -178,89 +155,77 @@ EventEmitter.prototype.emit = function emit (type: any) {
ReflectApply(listeners[i], this, args);
}
}
-
return true;
};
-
-function _addListener (target: any, type: any, listener: any, prepend: any) {
+function _addListener(target, type, listener, prepend) {
let m;
let events;
let existing;
-
checkListener(listener);
-
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
- // To avoid recursion in the case that type === "newListener"! Before
- // adding it to the listeners, first emit "newListener".
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit(
- 'newListener',
+ "newListener",
type,
- listener.listener ? listener.listener : listener
- );
-
- // Re-assign `events` because a newListener handler could have caused the
- // this._events to be assigned to a new object
+ listener.listener ? listener.listener : listener,
+ ); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
-
if (existing === undefined) {
- // Optimize the case of one listener. Don't need the extra array object.
+ // Optimize the case of one listener. Don't need the extra array object.
existing = events[type] = listener;
++target._eventsCount;
} else {
- if (typeof existing === 'function') {
- // Adding the second element, need to change to array.
+ if (typeof existing === "function") {
+ // Adding the second element, need to change to array.
existing = events[type] = prepend
? [listener, existing]
- : [existing, listener];
- // If we've already got an array, just append.
+ : [existing, listener]; // If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
- }
-
- // Check for listener leak
+ } // Check for listener leak
m = _getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
- existing.warned = true;
- // No error code for this since it is a Warning
- // eslint-disable-next-line no-restricted-syntax
- const w: any = new Error(
- 'Possible EventEmitter memory leak detected. ' +
- existing.length + ' ' + String(type) + ' listeners ' +
- 'added. Use emitter.setMaxListeners() to ' +
- 'increase limit'
+ existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax
+ const w = new Error(
+ "Possible EventEmitter memory leak detected. " +
+ existing.length +
+ " " +
+ String(type) +
+ " listeners " +
+ "added. Use emitter.setMaxListeners() to " +
+ "increase limit",
);
- w.name = 'MaxListenersExceededWarning';
+ w.name = "MaxListenersExceededWarning";
w.emitter = target;
w.type = type;
w.count = existing.length;
ProcessEmitWarning(w);
}
}
-
return target;
}
-
-EventEmitter.prototype.addListener = function addListener (type: any, listener: any) {
+EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
-
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.prependListener = function prependListener (type: any, listener: any) {
+EventEmitter.prototype.prependListener = function prependListener(
+ type,
+ listener,
+) {
return _addListener(this, type, listener, true);
};
-
-function onceWrapper (this: any) {
+function onceWrapper() {
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
@@ -270,63 +235,60 @@ function onceWrapper (this: any) {
return this.listener.apply(this.target, arguments);
}
}
-
-function _onceWrap (target: any, type: any, listener: any) {
+function _onceWrap(target, type, listener) {
const state = {
fired: false,
wrapFn: undefined,
target,
type,
- listener
+ listener,
};
- const wrapped: any = onceWrapper.bind(state);
+ const wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
-
-EventEmitter.prototype.once = function once (type: any, listener: any) {
+EventEmitter.prototype.once = function once(type, listener) {
checkListener(listener);
this.on(type, _onceWrap(this, type, listener));
return this;
};
-
-EventEmitter.prototype.prependOnceListener = function prependOnceListener (type: any, listener: any) {
+EventEmitter.prototype.prependOnceListener = function prependOnceListener(
+ type,
+ listener,
+) {
checkListener(listener);
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
-
-// Emits a 'removeListener' event if and only if the listener was removed.
-EventEmitter.prototype.removeListener = function removeListener (type: any, listener: any ) {
+// Emits a 'removeListener' event if and only if the listener was removed.
+EventEmitter.prototype.removeListener = function removeListener(
+ type,
+ listener,
+) {
const events = this._events;
const list = events[type];
let position;
let i;
let originalListener;
-
checkListener(listener);
-
if (events === undefined) {
return this;
}
-
if (list === undefined) {
return this;
}
-
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0) {
this._events = Object.create(null);
} else {
delete events[type];
if (events.removeListener) {
- this.emit('removeListener', type, list.listener || listener);
+ this.emit("removeListener", type, list.listener || listener);
}
}
- } else if (typeof list !== 'function') {
+ } else if (typeof list !== "function") {
position = -1;
-
for (i = list.length - 1; i >= 0; i--) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
@@ -334,41 +296,31 @@ EventEmitter.prototype.removeListener = function removeListener (type: any, list
break;
}
}
-
if (position < 0) {
return this;
}
-
if (position === 0) {
list.shift();
} else {
spliceOne(list, position);
}
-
if (list.length === 1) {
events[type] = list[0];
}
-
if (events.removeListener !== undefined) {
- this.emit('removeListener', type, originalListener || listener);
+ this.emit("removeListener", type, originalListener || listener);
}
}
-
return this;
};
-
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
-
-EventEmitter.prototype.removeAllListeners = function removeAllListeners (type: any) {
+EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
const events = this._events;
const listeners = events[type];
let i;
-
if (events === undefined) {
return this;
- }
-
- // not listening for removeListener, no need to emit
+ } // not listening for removeListener, no need to emit
if (events.removeListener === undefined) {
if (arguments.length === 0) {
this._events = Object.create(null);
@@ -381,155 +333,130 @@ EventEmitter.prototype.removeAllListeners = function removeAllListeners (type: a
}
}
return this;
- }
-
- // emit removeListener for all listeners on all events
+ } // emit removeListener for all listeners on all events
if (arguments.length === 0) {
const keys = Object.keys(events);
for (i = 0; i < keys.length; ++i) {
const key = keys[i];
- if (key === 'removeListener') continue;
+ if (key === "removeListener") continue;
this.removeAllListeners(key);
}
- this.removeAllListeners('removeListener');
+ this.removeAllListeners("removeListener");
this._events = Object.create(null);
this._eventsCount = 0;
return this;
}
-
- if (typeof listeners === 'function') {
+ if (typeof listeners === "function") {
this.removeListener(type, listeners);
} else if (listeners !== undefined) {
- // LIFO order
+ // LIFO order
for (i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
}
}
-
return this;
};
-
-function _listeners (target: any, type: any, unwrap: any) {
+function _listeners(target, type, unwrap) {
const events = target._events;
-
if (events === undefined) {
return [];
}
-
const evlistener = events[type];
if (evlistener === undefined) {
return [];
}
-
- if (typeof evlistener === 'function') {
+ if (typeof evlistener === "function") {
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
}
-
return unwrap
? unwrapListeners(evlistener)
: arrayClone(evlistener, evlistener.length);
}
-
-EventEmitter.prototype.listeners = function listeners (type: any) {
+EventEmitter.prototype.listeners = function listeners(type) {
return _listeners(this, type, true);
};
-
-EventEmitter.prototype.rawListeners = function rawListeners (type: any) {
+EventEmitter.prototype.rawListeners = function rawListeners(type) {
return _listeners(this, type, false);
};
-
-EventEmitter.listenerCount = function (emitter: any, type: any) {
- if (typeof emitter.listenerCount === 'function') {
+EventEmitter.listenerCount = function (emitter, type) {
+ if (typeof emitter.listenerCount === "function") {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
-
EventEmitter.prototype.listenerCount = listenerCount;
-function listenerCount (this: any, type: any) {
+function listenerCount(type) {
const events = this._events;
-
if (events !== undefined) {
const evlistener = events[type];
-
- if (typeof evlistener === 'function') {
+ if (typeof evlistener === "function") {
return 1;
} else if (evlistener !== undefined) {
return evlistener.length;
}
}
-
return 0;
}
-
-EventEmitter.prototype.eventNames = function eventNames () {
+EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
-
-function arrayClone (arr: any, n: any) {
+function arrayClone(arr, n) {
const copy = new Array(n);
for (let i = 0; i < n; ++i) {
copy[i] = arr[i];
}
return copy;
}
-
-function spliceOne (list: any, index: any) {
+function spliceOne(list, index) {
for (; index + 1 < list.length; index++) {
list[index] = list[index + 1];
}
list.pop();
}
-
-function unwrapListeners (arr: any) {
+function unwrapListeners(arr) {
const ret = new Array(arr.length);
for (let i = 0; i < ret.length; ++i) {
ret[i] = arr[i].listener || arr[i];
}
return ret;
}
-
-function once (emitter: any, name: any) {
+function once(emitter, name) {
return new Promise(function (resolve, reject) {
- function errorListener (err: Error) {
+ function errorListener(err) {
emitter.removeListener(name, resolver);
reject(err);
}
-
- function resolver () {
- if (typeof emitter.removeListener === 'function') {
- emitter.removeListener('error', errorListener);
+ function resolver() {
+ if (typeof emitter.removeListener === "function") {
+ emitter.removeListener("error", errorListener);
}
resolve([].slice.call(arguments));
}
-
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
- if (name !== 'error') {
+ if (name !== "error") {
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
}
});
}
-
-function addErrorHandlerIfEventEmitter (emitter: any, handler: any, flags: any) {
- if (typeof emitter.on === 'function') {
- eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
+function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
+ if (typeof emitter.on === "function") {
+ eventTargetAgnosticAddListener(emitter, "error", handler, flags);
}
}
-
-function eventTargetAgnosticAddListener (emitter: any, name: any, listener: any, flags: any) {
- if (typeof emitter.on === 'function') {
+function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
+ if (typeof emitter.on === "function") {
if (flags.once) {
emitter.once(name, listener);
} else {
emitter.on(name, listener);
}
- } else if (typeof emitter.addEventListener === 'function') {
- // EventTarget does not have `error` event semantics like Node
- // EventEmitters, we do not listen for `error` events here.
- emitter.addEventListener(name, function wrapListener (arg: any) {
- // IE does not have builtin `{ once: true }` support so we
- // have to do it manually.
+ } else if (typeof emitter.addEventListener === "function") {
+ // EventTarget does not have `error` event semantics like Node
+ // EventEmitters, we do not listen for `error` events here.
+ emitter.addEventListener(name, function wrapListener(arg) {
+ // IE does not have builtin `{ once: true }` support so we
+ // have to do it manually.
if (flags.once) {
emitter.removeEventListener(name, wrapListener);
}
@@ -537,10 +464,9 @@ function eventTargetAgnosticAddListener (emitter: any, name: any, listener: any,
});
} else {
throw new TypeError(
- 'The "emitter" argument must be of type EventEmitter. Received type ' +
- typeof emitter
+ 'The "emitter" argument must be of type EventEmitter. Received type ' +
+ typeof emitter,
);
}
}
-
export { EventEmitter };
diff --git a/main/commons/src/index.ts b/main/commons/src/index.ts
index c77f51ad0f..273c78aae2 100644
--- a/main/commons/src/index.ts
+++ b/main/commons/src/index.ts
@@ -1,69 +1,69 @@
-export * from './testing.ts';
+export * from "./testing.ts";
// Removes all leading and trailing slashes from a path
-export function stripSlashes (name: string) {
- return name.replace(/^(\/+)|(\/+)$/g, '');
+export function stripSlashes(name: string) {
+ return name.replace(/^(\/+)|(\/+)$/g, "");
}
export type KeyValueCallback = (value: any, key: string) => T;
// A set of lodash-y utility functions that use ES6
export const _ = {
- each (obj: any, callback: KeyValueCallback) {
- if (obj && typeof obj.forEach === 'function') {
+ each(obj: any, callback: KeyValueCallback) {
+ if (obj && typeof obj.forEach === "function") {
obj.forEach(callback);
} else if (_.isObject(obj)) {
- Object.keys(obj).forEach(key => callback(obj[key], key));
+ Object.keys(obj).forEach((key) => callback(obj[key], key));
}
},
- some (value: any, callback: KeyValueCallback) {
+ some(value: any, callback: KeyValueCallback) {
return Object.keys(value)
- .map(key => [ value[key], key ])
+ .map((key) => [value[key], key])
.some(([val, key]) => callback(val, key));
},
- every (value: any, callback: KeyValueCallback) {
+ every(value: any, callback: KeyValueCallback) {
return Object.keys(value)
- .map(key => [ value[key], key ])
+ .map((key) => [value[key], key])
.every(([val, key]) => callback(val, key));
},
- keys (obj: any) {
+ keys(obj: any) {
return Object.keys(obj);
},
- values (obj: any) {
- return _.keys(obj).map(key => obj[key]);
+ values(obj: any) {
+ return _.keys(obj).map((key) => obj[key]);
},
- isMatch (obj: any, item: any) {
- return _.keys(item).every(key => obj[key] === item[key]);
+ isMatch(obj: any, item: any) {
+ return _.keys(item).every((key) => obj[key] === item[key]);
},
- isEmpty (obj: any) {
+ isEmpty(obj: any) {
return _.keys(obj).length === 0;
},
- isObject (item: any) {
- return (typeof item === 'object' && !Array.isArray(item) && item !== null);
+ isObject(item: any) {
+ return typeof item === "object" && !Array.isArray(item) && item !== null;
},
- isObjectOrArray (value: any) {
- return typeof value === 'object' && value !== null;
+ isObjectOrArray(value: any) {
+ return typeof value === "object" && value !== null;
},
- extend (first: any, ...rest: any[]) {
+ extend(first: any, ...rest: any[]) {
return Object.assign(first, ...rest);
},
- omit (obj: any, ...keys: string[]) {
+ omit(obj: any, ...keys: string[]) {
const result = _.extend({}, obj);
- keys.forEach(key => delete result[key]);
+ keys.forEach((key) => delete result[key]);
return result;
},
- pick (source: any, ...keys: string[]) {
+ pick(source: any, ...keys: string[]) {
return keys.reduce((result: { [key: string]: any }, key) => {
if (source[key] !== undefined) {
result[key] = source[key];
@@ -74,9 +74,9 @@ export const _ = {
},
// Recursively merge the source object into the target object
- merge (target: any, source: any) {
+ merge(target: any, source: any) {
if (_.isObject(target) && _.isObject(source)) {
- Object.keys(source).forEach(key => {
+ Object.keys(source).forEach((key) => {
if (_.isObject(source[key])) {
if (!target[key]) {
Object.assign(target, { [key]: {} });
@@ -89,17 +89,18 @@ export const _ = {
});
}
return target;
- }
+ },
};
// Duck-checks if an object looks like a promise
-export function isPromise (result: any) {
- return _.isObject(result) &&
- typeof result.then === 'function';
+export function isPromise(result: any) {
+ return _.isObject(result) && typeof result.then === "function";
}
-export function createSymbol (name: string) {
- return typeof Symbol !== 'undefined' ? Symbol(name) : name;
+export function createSymbol(name: string) {
+ return typeof Symbol !== "undefined" ? Symbol(name) : name;
}
-export * from './debug.ts';
+export * from "./debug.ts";
+
+export * from "./events.js";
diff --git a/main/commons/src/testing.ts b/main/commons/src/testing.ts
index a4b438e101..55bbaffacd 100644
--- a/main/commons/src/testing.ts
+++ b/main/commons/src/testing.ts
@@ -1,20 +1,16 @@
// https://deno.land/manual/testing/assertions
-import * as denoAssert from 'https://deno.land/std@0.114.0/testing/asserts.ts';
+import * as denoAssert from "https://deno.land/std@0.159.0/testing/asserts.ts";
-const { assertEquals } = denoAssert
+const { assertEquals } = denoAssert;
-export * from 'https://deno.land/std@0.114.0/testing/asserts.ts';
+export * from "https://deno.land/std@0.159.0/testing/bdd.ts";
-export const it = (name: string, fn: () => any, only = false) => Deno.test({
- only,
- name,
- fn
-});
+export * from "https://deno.land/std@0.159.0/testing/asserts.ts";
-it.only = (name: string, fn: () => any) => it(name, fn, true);
-
-export const assert = {
- deepStrictEqual (actual: unknown, expected: unknown, msg?: string) {
- return assertEquals(actual, expected, msg)
- }
+export function assertDeepStrictEquals(
+ actual: unknown,
+ expected: unknown,
+ msg?: string
+) {
+ return assertEquals(actual, expected, msg);
}
diff --git a/main/commons/test/debug.test.ts b/main/commons/test/debug.test.ts
index eac1f9f8c1..80a83afd2a 100644
--- a/main/commons/test/debug.test.ts
+++ b/main/commons/test/debug.test.ts
@@ -1,28 +1,30 @@
-import { it, assertEquals, assertStrictEquals } from '../src/testing.ts';
-import { createDebug, setDebug, noopDebug } from '../src/index.ts';
+import { it, assertEquals, assertStrictEquals } from "../src/testing.ts";
+import { createDebug, setDebug, noopDebug } from "../src/index.ts";
-const myDebug = createDebug('hello test');
+const myDebug = createDebug("hello test");
-it('default debug does nothing', () => {
- assertStrictEquals(myDebug('hi', 'there'), undefined);
+it("default debug does nothing", () => {
+ assertStrictEquals(myDebug("hi", "there"), undefined);
});
-it('can set custom debug later', () => {
+it("can set custom debug later", () => {
let call;
- const customDebug = (name: string) => (...args: any[]) => {
- call = [ name ].concat(args);
- }
+ const customDebug =
+ (name: string) =>
+ (...args: any[]) => {
+ call = [name].concat(args);
+ };
setDebug(customDebug);
- assertStrictEquals(myDebug('hi', 'there'), undefined);
- assertEquals(call, [ 'hello test', 'hi', 'there' ]);
+ assertStrictEquals(myDebug("hi", "there"), undefined);
+ assertEquals(call, ["hello test", "hi", "there"]);
- const newDebug = createDebug('other test');
+ const newDebug = createDebug("other test");
- assertStrictEquals(newDebug('other', 'there'), undefined);
- assertEquals(call, [ 'other test', 'other', 'there' ]);
+ assertStrictEquals(newDebug("other", "there"), undefined);
+ assertEquals(call, ["other test", "other", "there"]);
setDebug(noopDebug);
});
diff --git a/main/commons/test/module.test.ts b/main/commons/test/module.test.ts
index b64291d195..6755594fde 100644
--- a/main/commons/test/module.test.ts
+++ b/main/commons/test/module.test.ts
@@ -1,24 +1,24 @@
-import { it, assertStrictEquals } from '../src/testing.ts';
-import { _ } from '../src/index.ts';
-import * as commons from '../src/index.ts'
+import { it, assertStrictEquals } from "../src/testing.ts";
+import { _ } from "../src/index.ts";
+import * as commons from "../src/index.ts";
-it('commons: is commonjs compatible', () => {
- assertStrictEquals(typeof commons, 'object');
- assertStrictEquals(typeof commons.stripSlashes, 'function');
- assertStrictEquals(typeof commons._, 'object');
+it("commons: is commonjs compatible", () => {
+ assertStrictEquals(typeof commons, "object");
+ assertStrictEquals(typeof commons.stripSlashes, "function");
+ assertStrictEquals(typeof commons._, "object");
});
-it('commons: exposes lodash methods under _', () => {
- assertStrictEquals(typeof _.each, 'function');
- assertStrictEquals(typeof _.some, 'function');
- assertStrictEquals(typeof _.every, 'function');
- assertStrictEquals(typeof _.keys, 'function');
- assertStrictEquals(typeof _.values, 'function');
- assertStrictEquals(typeof _.isMatch, 'function');
- assertStrictEquals(typeof _.isEmpty, 'function');
- assertStrictEquals(typeof _.isObject, 'function');
- assertStrictEquals(typeof _.extend, 'function');
- assertStrictEquals(typeof _.omit, 'function');
- assertStrictEquals(typeof _.pick, 'function');
- assertStrictEquals(typeof _.merge, 'function');
+it("commons: exposes lodash methods under _", () => {
+ assertStrictEquals(typeof _.each, "function");
+ assertStrictEquals(typeof _.some, "function");
+ assertStrictEquals(typeof _.every, "function");
+ assertStrictEquals(typeof _.keys, "function");
+ assertStrictEquals(typeof _.values, "function");
+ assertStrictEquals(typeof _.isMatch, "function");
+ assertStrictEquals(typeof _.isEmpty, "function");
+ assertStrictEquals(typeof _.isObject, "function");
+ assertStrictEquals(typeof _.extend, "function");
+ assertStrictEquals(typeof _.omit, "function");
+ assertStrictEquals(typeof _.pick, "function");
+ assertStrictEquals(typeof _.merge, "function");
});
diff --git a/main/commons/test/utils.test.ts b/main/commons/test/utils.test.ts
index 7eb07dca9b..f16dbb0c42 100644
--- a/main/commons/test/utils.test.ts
+++ b/main/commons/test/utils.test.ts
@@ -1,161 +1,217 @@
/* tslint:disable:no-unused-expression */
-import { it, assert, assertEquals, assertStrictEquals } from '../src/testing.ts';
-import { _, stripSlashes, isPromise, createSymbol } from '../src/index.ts';
-
-it('stripSlashes', () => {
- assertStrictEquals(stripSlashes('some/thing'), 'some/thing');
- assertStrictEquals(stripSlashes('/some/thing'), 'some/thing');
- assertStrictEquals(stripSlashes('some/thing/'), 'some/thing');
- assertStrictEquals(stripSlashes('/some/thing/'), 'some/thing');
- assertStrictEquals(stripSlashes('//some/thing/'), 'some/thing');
- assertStrictEquals(stripSlashes('//some//thing////'), 'some//thing');
-});
-
-it('isPromise', () => {
+import {
+ it,
+ assert,
+ assertEquals,
+ assertStrictEquals,
+} from "../src/testing.ts";
+import { _, stripSlashes, isPromise, createSymbol } from "../src/index.ts";
+
+it("stripSlashes", () => {
+ assertStrictEquals(stripSlashes("some/thing"), "some/thing");
+ assertStrictEquals(stripSlashes("/some/thing"), "some/thing");
+ assertStrictEquals(stripSlashes("some/thing/"), "some/thing");
+ assertStrictEquals(stripSlashes("/some/thing/"), "some/thing");
+ assertStrictEquals(stripSlashes("//some/thing/"), "some/thing");
+ assertStrictEquals(stripSlashes("//some//thing////"), "some//thing");
+});
+
+it("isPromise", () => {
assertStrictEquals(isPromise(Promise.resolve()), true);
- assert(isPromise({
- then () {}
- }));
+ assert(
+ isPromise({
+ then() {},
+ })
+ );
assertStrictEquals(isPromise(null), false);
});
-it('createSymbol', () => {
- assertStrictEquals(typeof createSymbol('a test'), 'symbol');
+it("createSymbol", () => {
+ assertStrictEquals(typeof createSymbol("a test"), "symbol");
});
-it('isObject', () => {
+it("isObject", () => {
assertStrictEquals(_.isObject({}), true);
assertStrictEquals(_.isObject([]), false);
assertStrictEquals(_.isObject(null), false);
});
-it('isObjectOrArray', () => {
+it("isObjectOrArray", () => {
assertStrictEquals(_.isObjectOrArray({}), true);
assertStrictEquals(_.isObjectOrArray([]), true);
assertStrictEquals(_.isObjectOrArray(null), false);
});
-it('each', () => {
- _.each({ hi: 'there' }, (value, key) => {
- assertStrictEquals(key, 'hi');
- assertStrictEquals(value, 'there');
+it("each", () => {
+ _.each({ hi: "there" }, (value, key) => {
+ assertStrictEquals(key, "hi");
+ assertStrictEquals(value, "there");
});
- _.each([ 'hi' ], (value, key) => {
+ _.each(["hi"], (value, key) => {
assertStrictEquals(key, 0);
- assertStrictEquals(value, 'hi');
+ assertStrictEquals(value, "hi");
});
- _.each('moo', () => {
- throw new Error('Should never get here')
+ _.each("moo", () => {
+ throw new Error("Should never get here");
});
});
-it('some', () => {
- assert(_.some([ 'a', 'b' ], current => current === 'a'));
- assert(!_.some([ 'a', 'b' ], current => current === 'c'));
+it("some", () => {
+ assert(_.some(["a", "b"], (current) => current === "a"));
+ assert(!_.some(["a", "b"], (current) => current === "c"));
});
-it('every', () => {
- assert(_.every([ 'a', 'a' ], current => current === 'a'));
- assert(!_.every([ 'a', 'b' ], current => current === 'a'));
+it("every", () => {
+ assert(_.every(["a", "a"], (current) => current === "a"));
+ assert(!_.every(["a", "b"], (current) => current === "a"));
});
-it('keys', () => {
- const data = { hi: 'there', name: 'David' };
- assertEquals(_.keys(data), [ 'hi', 'name' ]);
+it("keys", () => {
+ const data = { hi: "there", name: "David" };
+ assertEquals(_.keys(data), ["hi", "name"]);
});
-it('values', () => {
- const data = { hi: 'there', name: 'David' };
- assertEquals(_.values(data), [ 'there', 'David' ]);
+it("values", () => {
+ const data = { hi: "there", name: "David" };
+ assertEquals(_.values(data), ["there", "David"]);
});
-it('isMatch', () => {
- assert(_.isMatch({
- test: 'me', hi: 'you', more: true
- }, {
- test: 'me', hi: 'you'
- }));
+it("isMatch", () => {
+ assert(
+ _.isMatch(
+ {
+ test: "me",
+ hi: "you",
+ more: true,
+ },
+ {
+ test: "me",
+ hi: "you",
+ }
+ )
+ );
- assert(!_.isMatch({
- test: 'me', hi: 'you', more: true
- }, {
- test: 'me', hi: 'there'
- }));
+ assert(
+ !_.isMatch(
+ {
+ test: "me",
+ hi: "you",
+ more: true,
+ },
+ {
+ test: "me",
+ hi: "there",
+ }
+ )
+ );
});
-it('isEmpty', () => {
+it("isEmpty", () => {
assert(_.isEmpty({}));
- assert(!_.isEmpty({ name: 'David' }));
-});
-
-it('extend', () => {
- assertEquals(_.extend({ hi: 'there' }, { name: 'david' }), {
- hi: 'there',
- name: 'david'
- });
+ assert(!_.isEmpty({ name: "David" }));
});
-it('omit', () => {
- assertEquals(_.omit({
- name: 'David',
- first: 1,
- second: 2
- }, 'first', 'second'), {
- name: 'David'
+it("extend", () => {
+ assertEquals(_.extend({ hi: "there" }, { name: "david" }), {
+ hi: "there",
+ name: "david",
});
});
-it('pick', () => {
- assertEquals(_.pick({
- name: 'David',
- first: 1,
- second: 2
- }, 'first', 'second'), {
- first: 1,
- second: 2
- });
-
- assertEquals(_.pick({
- name: 'David',
- first: 1
- }, 'first', 'second'), {
- first: 1
- });
+it("omit", () => {
+ assertEquals(
+ _.omit(
+ {
+ name: "David",
+ first: 1,
+ second: 2,
+ },
+ "first",
+ "second"
+ ),
+ {
+ name: "David",
+ }
+ );
+});
+
+it("pick", () => {
+ assertEquals(
+ _.pick(
+ {
+ name: "David",
+ first: 1,
+ second: 2,
+ },
+ "first",
+ "second"
+ ),
+ {
+ first: 1,
+ second: 2,
+ }
+ );
+
+ assertEquals(
+ _.pick(
+ {
+ name: "David",
+ first: 1,
+ },
+ "first",
+ "second"
+ ),
+ {
+ first: 1,
+ }
+ );
});
-it('merge', () => {
- assertEquals(_.merge({ hi: 'there' }, { name: 'david' }), {
- hi: 'there',
- name: 'david'
+it("merge", () => {
+ assertEquals(_.merge({ hi: "there" }, { name: "david" }), {
+ hi: "there",
+ name: "david",
});
- assertEquals(_.merge({}, {
- name: 'david',
- nested: { obj: true }
- }), {
- name: 'david',
- nested: { obj: true }
- });
+ assertEquals(
+ _.merge(
+ {},
+ {
+ name: "david",
+ nested: { obj: true },
+ }
+ ),
+ {
+ name: "david",
+ nested: { obj: true },
+ }
+ );
- assertEquals(_.merge({ name: 'david' }, {}), {
- name: 'david'
+ assertEquals(_.merge({ name: "david" }, {}), {
+ name: "david",
});
- assertEquals(_.merge({
- hi: 'there',
- my: {
- name: { is: 'david' },
- number: { is: 1 }
+ assertEquals(
+ _.merge(
+ {
+ hi: "there",
+ my: {
+ name: { is: "david" },
+ number: { is: 1 },
+ },
+ },
+ { my: { name: { is: "eric" } } }
+ ),
+ {
+ hi: "there",
+ my: {
+ number: { is: 1 },
+ name: { is: "eric" },
+ },
}
- }, { my: { name: { is: 'eric' } } }), {
- hi: 'there',
- my: {
- number: { is: 1 },
- name: { is: 'eric' }
- }
- });
+ );
- assertStrictEquals(_.merge('hello', {}), 'hello');
+ assertStrictEquals(_.merge("hello", {}), "hello");
});
diff --git a/main/errors/LICENSE b/main/errors/LICENSE
index 3f395cc665..59604f46f3 100644
--- a/main/errors/LICENSE
+++ b/main/errors/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2021 Feathers
+Copyright (c) 2022 Feathers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/main/errors/mod.ts b/main/errors/mod.ts
new file mode 100644
index 0000000000..3b3419b271
--- /dev/null
+++ b/main/errors/mod.ts
@@ -0,0 +1 @@
+export * from "./src/index.ts";
diff --git a/main/errors/src/index.ts b/main/errors/src/index.ts
index 8d7e155356..e9b99d69d1 100644
--- a/main/errors/src/index.ts
+++ b/main/errors/src/index.ts
@@ -8,9 +8,14 @@ export interface FeathersErrorJSON {
}
export type DynamicError = Error & { [key: string]: any };
-export type ErrorMessage = string | DynamicError | { [key: string]: any } | any[];
-
-interface ErrorProperties extends Omit {
+export type ErrorMessage =
+ | null
+ | string
+ | DynamicError
+ | { [key: string]: any }
+ | any[];
+
+interface ErrorProperties extends Omit {
type: string;
}
@@ -21,19 +26,26 @@ export class FeathersError extends Error {
readonly data: any;
readonly errors: any;
- constructor (err: ErrorMessage | undefined, name: string, code: number, className: string, _data: any) {
- let msg = typeof err === 'string' ? err : 'Error';
+ constructor(
+ err: ErrorMessage | undefined,
+ name: string,
+ code: number,
+ className: string,
+ _data: any
+ ) {
+ let msg = typeof err === "string" ? err : "Error";
const properties: ErrorProperties = {
name,
code,
className,
- type: 'FeathersError'
+ type: "FeathersError",
};
if (Array.isArray(_data)) {
properties.data = _data;
- } else if (typeof err === 'object' || _data !== undefined) {
- const { message, errors, ...rest } = typeof err === 'object' ? err : _data;
+ } else if (typeof err === "object" || _data !== undefined) {
+ const { message, errors, ...rest } =
+ err !== null && typeof err === "object" ? err : _data;
msg = message || msg;
properties.errors = errors;
@@ -44,12 +56,12 @@ export class FeathersError extends Error {
Object.assign(this, properties);
}
- toJSON () {
+ toJSON() {
const result: FeathersErrorJSON = {
name: this.name,
message: this.message,
code: this.code,
- className: this.className
+ className: this.className,
};
if (this.data !== undefined) {
@@ -65,120 +77,120 @@ export class FeathersError extends Error {
}
export class BadRequest extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'BadRequest', 400, 'bad-request', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "BadRequest", 400, "bad-request", data);
}
}
// 401 - Not Authenticated
-export class NotAuthenticated extends FeathersError{
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'NotAuthenticated', 401, 'not-authenticated', data);
+export class NotAuthenticated extends FeathersError {
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "NotAuthenticated", 401, "not-authenticated", data);
}
}
// 402 - Payment Error
export class PaymentError extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'PaymentError', 402, 'payment-error', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "PaymentError", 402, "payment-error", data);
}
}
// 403 - Forbidden
export class Forbidden extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Forbidden', 403, 'forbidden', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Forbidden", 403, "forbidden", data);
}
}
// 404 - Not Found
export class NotFound extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'NotFound', 404, 'not-found', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "NotFound", 404, "not-found", data);
}
}
// 405 - Method Not Allowed
export class MethodNotAllowed extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'MethodNotAllowed', 405, 'method-not-allowed', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "MethodNotAllowed", 405, "method-not-allowed", data);
}
}
// 406 - Not Acceptable
export class NotAcceptable extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'NotAcceptable', 406, 'not-acceptable', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "NotAcceptable", 406, "not-acceptable", data);
}
}
// 408 - Timeout
export class Timeout extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Timeout', 408, 'timeout', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Timeout", 408, "timeout", data);
}
}
// 409 - Conflict
export class Conflict extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Conflict', 409, 'conflict', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Conflict", 409, "conflict", data);
}
}
// 410 - Gone
export class Gone extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Gone', 410, 'gone', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Gone", 410, "gone", data);
}
}
// 411 - Length Required
export class LengthRequired extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'LengthRequired', 411, 'length-required', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "LengthRequired", 411, "length-required", data);
}
}
// 422 Unprocessable
export class Unprocessable extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Unprocessable', 422, 'unprocessable', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Unprocessable", 422, "unprocessable", data);
}
}
// 429 Too Many Requests
export class TooManyRequests extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'TooManyRequests', 429, 'too-many-requests', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "TooManyRequests", 429, "too-many-requests", data);
}
}
// 500 - General Error
export class GeneralError extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'GeneralError', 500, 'general-error', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "GeneralError", 500, "general-error", data);
}
}
// 501 - Not Implemented
export class NotImplemented extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'NotImplemented', 501, 'not-implemented', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "NotImplemented", 501, "not-implemented", data);
}
}
// 502 - Bad Gateway
export class BadGateway extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'BadGateway', 502, 'bad-gateway', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "BadGateway", 502, "bad-gateway", data);
}
}
// 503 - Unavailable
export class Unavailable extends FeathersError {
- constructor (message?: ErrorMessage, data?: any) {
- super(message, 'Unavailable', 503, 'unavailable', data);
+ constructor(message?: ErrorMessage, data?: any) {
+ super(message, "Unavailable", 503, "unavailable", data);
}
}
@@ -252,10 +264,10 @@ export const errors = {
500: GeneralError,
501: NotImplemented,
502: BadGateway,
- 503: Unavailable
-}
+ 503: Unavailable,
+};
-export function convert (error: any) {
+export function convert(error: any) {
if (!error) {
return error;
}
@@ -265,7 +277,7 @@ export function convert (error: any) {
? new FeathersError(error.message, error.data)
: new Error(error.message || error);
- if (typeof error === 'object') {
+ if (typeof error === "object") {
Object.assign(result, error);
}
diff --git a/main/feathers/LICENSE b/main/feathers/LICENSE
new file mode 100644
index 0000000000..59604f46f3
--- /dev/null
+++ b/main/feathers/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2022 Feathers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/readme.md b/main/feathers/README.md
similarity index 85%
rename from readme.md
rename to main/feathers/README.md
index 4890b8cee7..246462b472 100644
--- a/readme.md
+++ b/main/feathers/README.md
@@ -1,39 +1,37 @@
-
-
-## A framework for real-time applications and REST APIs with JavaScript and TypeScript
-
-[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)
-[![Maintainability](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/maintainability)](https://codeclimate.com/github/feathersjs/feathers/maintainability)
-[![Test Coverage](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/test_coverage)](https://codeclimate.com/github/feathersjs/feathers/test_coverage)
-[![Download Status](https://img.shields.io/npm/dm/@feathersjs/feathers.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)
-
-[![Slack Status](https://img.shields.io/badge/Slack-Join-brightgreen)](http://slack.feathersjs.com)
-[![Telegram Status](https://img.shields.io/badge/Telegram_RU_chat:-Feathers-216bc1.svg?style=flat)](https://t.me/featherjs)
-
-Feathers is a lightweight web-framework for creating real-time applications and REST APIs using JavaScript or TypeScript.
-
-Feathers can interact with any backend technology, supports over a dozen databases and works with any frontend technology like React, VueJS, Angular, React Native, Android or iOS.
-
-## Getting started
-
-You can build your first real-time and REST API in just 4 commands:
-
-```bash
-$ npm install -g @feathersjs/cli
-$ mkdir my-new-app
-$ cd my-new-app/
-$ feathers generate app
-$ npm start
-```
-
-To learn more about Feathers visit the website at [feathersjs.com](http://feathersjs.com) or jump right into [the Feathers guides](http://docs.feathersjs.com/guides).
-
-## Documentation
-
-The [Feathers docs](http://docs.feathersjs.com) are loaded with awesome stuff and tell you every thing you need to know about using and configuring Feathers.
-
-## License
-
-Copyright (c) 2021 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)
-
-Licensed under the [MIT license](LICENSE).
+
+
+## A framework for real-time applications and REST APIs with JavaScript and TypeScript
+
+[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)
+[![Maintainability](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/maintainability)](https://codeclimate.com/github/feathersjs/feathers/maintainability)
+[![Test Coverage](https://api.codeclimate.com/v1/badges/cb5ec42a2d0cc1a47a02/test_coverage)](https://codeclimate.com/github/feathersjs/feathers/test_coverage)
+[![Download Status](https://img.shields.io/npm/dm/@feathersjs/feathers.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)
+[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)
+
+Feathers is a lightweight web-framework for creating real-time applications and REST APIs using JavaScript or TypeScript.
+
+Feathers can interact with any backend technology, supports over a dozen databases and works with any frontend technology like React, VueJS, Angular, React Native, Android or iOS.
+
+## Getting started
+
+You can build your first real-time and REST API in just 4 commands:
+
+```bash
+$ npm install -g @feathersjs/cli
+$ mkdir my-new-app
+$ cd my-new-app/
+$ feathers generate app
+$ npm start
+```
+
+To learn more about Feathers visit the website at [feathersjs.com](http://feathersjs.com) or jump right into [the Feathers guides](http://docs.feathersjs.com/guides).
+
+## Documentation
+
+The [Feathers docs](http://docs.feathersjs.com) are loaded with awesome stuff and tell you every thing you need to know about using and configuring Feathers.
+
+## License
+
+Copyright (c) 2022 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)
+
+Licensed under the [MIT license](LICENSE).
diff --git a/main/feathers/mod.ts b/main/feathers/mod.ts
new file mode 100644
index 0000000000..3b3419b271
--- /dev/null
+++ b/main/feathers/mod.ts
@@ -0,0 +1 @@
+export * from "./src/index.ts";
diff --git a/main/feathers/src/application.ts b/main/feathers/src/application.ts
new file mode 100644
index 0000000000..19db08556f
--- /dev/null
+++ b/main/feathers/src/application.ts
@@ -0,0 +1,253 @@
+import version from "./version.ts";
+import { EventEmitter } from "../../commons/mod.ts";
+import { stripSlashes, createDebug } from "../../commons/mod.ts";
+import {
+ HOOKS,
+ hooks,
+ middleware,
+} from "https://deno.land/x/hooks@v0.7.5/src/index.ts";
+import { eventHook, eventMixin } from "./events.ts";
+import { hookMixin } from "./hooks.ts";
+import { wrapService, getServiceOptions, protectedMethods } from "./service.ts";
+import {
+ FeathersApplication,
+ ServiceMixin,
+ Service,
+ ServiceOptions,
+ ServiceInterface,
+ Application,
+ FeathersService,
+ ApplicationHookOptions,
+} from "./declarations.ts";
+import { enableHooks } from "./hooks.ts";
+
+const debug = createDebug("@feathersjs/feathers");
+
+export class Feathers
+ extends EventEmitter
+ implements FeathersApplication
+{
+ services: Services = {} as Services;
+ settings: Settings = {} as Settings;
+ mixins: ServiceMixin>[] = [
+ hookMixin,
+ eventMixin,
+ ];
+ version: string = version;
+ _isSetup = false;
+
+ protected registerHooks: (this: any, allHooks: any) => any;
+
+ constructor() {
+ super();
+ this.registerHooks = enableHooks(this);
+ this.registerHooks({
+ around: [eventHook],
+ });
+ }
+
+ get(name: L): Settings[L] {
+ return this.settings[name];
+ }
+
+ set(name: L, value: Settings[L]) {
+ this.settings[name] = value;
+ return this;
+ }
+
+ configure(callback: (this: this, app: this) => void) {
+ callback.call(this, this);
+
+ return this;
+ }
+
+ defaultService(location: string): ServiceInterface {
+ throw new Error(`Can not find service '${location}'`);
+ }
+
+ service(
+ location: L
+ ): FeathersService<
+ this,
+ keyof any extends keyof Services ? Service : Services[L]
+ > {
+ const path = (stripSlashes(location) || "/") as L;
+ const current = this.services[path];
+
+ if (typeof current === "undefined") {
+ this.use(path, this.defaultService(path) as any);
+ return this.service(path);
+ }
+
+ return current as any;
+ }
+
+ protected _setup() {
+ this._isSetup = true;
+
+ return Object.keys(this.services as object)
+ .reduce(
+ (current, path) =>
+ current.then(() => {
+ const service: any = this.service(path as any);
+
+ if (typeof service.setup === "function") {
+ debug(`Setting up service for \`${path}\``);
+
+ return service.setup(this, path);
+ }
+ }),
+ Promise.resolve()
+ )
+ .then(() => this);
+ }
+
+ get setup() {
+ return this._setup;
+ }
+
+ set setup(value) {
+ this._setup = (value as any)[HOOKS]
+ ? value
+ : hooks(
+ value,
+ middleware().params("server").props({
+ app: this,
+ })
+ );
+ }
+
+ protected _teardown() {
+ this._isSetup = false;
+
+ return Object.keys(this.services as object)
+ .reduce(
+ (current, path) =>
+ current.then(() => {
+ const service: any = this.service(path as any);
+
+ if (typeof service.teardown === "function") {
+ debug(`Tearing down service for \`${path}\``);
+
+ return service.teardown(this, path);
+ }
+ }),
+ Promise.resolve()
+ )
+ .then(() => this);
+ }
+
+ get teardown() {
+ return this._teardown;
+ }
+
+ set teardown(value) {
+ this._teardown = (value as any)[HOOKS]
+ ? value
+ : hooks(
+ value,
+ middleware().params("server").props({
+ app: this,
+ })
+ );
+ }
+
+ use(
+ path: L,
+ service: keyof any extends keyof Services
+ ? ServiceInterface | Application
+ : Services[L],
+ options?: ServiceOptions
+ ): this {
+ if (typeof path !== "string") {
+ throw new Error(`'${path}' is not a valid service path.`);
+ }
+
+ const location = (stripSlashes(path) || "/") as L;
+ const subApp = service as Application;
+ const isSubApp = typeof subApp.service === "function" && subApp.services;
+
+ if (isSubApp) {
+ Object.keys(subApp.services).forEach((subPath) =>
+ this.use(
+ `${location}/${subPath}` as any,
+ subApp.service(subPath) as any
+ )
+ );
+
+ return this;
+ }
+
+ const protoService = wrapService(location, service, options);
+ const serviceOptions = getServiceOptions(protoService);
+
+ for (const name of protectedMethods) {
+ if (serviceOptions.methods?.includes(name)) {
+ throw new Error(
+ `'${name}' on service '${location}' is not allowed as a custom method name`
+ );
+ }
+ }
+
+ debug(`Registering new service at \`${location}\``);
+
+ // Add all the mixins
+ this.mixins.forEach((fn) =>
+ fn.call(this, protoService, location, serviceOptions)
+ );
+
+ this.services[location] = protoService;
+
+ // If we ran setup already, set this service up explicitly, this will not `await`
+ if (this._isSetup && typeof protoService.setup === "function") {
+ debug(`Setting up service for \`${location}\``);
+ protoService.setup(this, location);
+ }
+
+ return this;
+ }
+
+ async unuse(
+ location: L
+ ): Promise<
+ FeathersService<
+ this,
+ keyof any extends keyof Services ? Service : Services[L]
+ >
+ > {
+ const path = (stripSlashes(location) || "/") as L;
+ const service = this.services[path] as Service;
+
+ if (service && typeof service.teardown === "function") {
+ await service.teardown(this as any, path);
+ }
+
+ delete this.services[path];
+
+ return service as any;
+ }
+
+ hooks(hookMap: ApplicationHookOptions) {
+ const untypedMap = hookMap as any;
+
+ if (
+ untypedMap.before ||
+ untypedMap.after ||
+ untypedMap.error ||
+ untypedMap.around
+ ) {
+ // regular hooks for all service methods
+ this.registerHooks(untypedMap);
+ } else if (untypedMap.setup || untypedMap.teardown) {
+ // .setup and .teardown application hooks
+ hooks(this, untypedMap);
+ } else {
+ // Other registration formats are just `around` hooks
+ this.registerHooks({
+ around: untypedMap,
+ });
+ }
+
+ return this;
+ }
+}
diff --git a/main/feathers/src/declarations.ts b/main/feathers/src/declarations.ts
new file mode 100644
index 0000000000..ec9b062c5d
--- /dev/null
+++ b/main/feathers/src/declarations.ts
@@ -0,0 +1,499 @@
+import { EventEmitter } from "../../commons/mod.ts";
+import {
+ NextFunction,
+ HookContext as BaseHookContext,
+} from "https://deno.land/x/hooks@v0.7.5/src/index.ts";
+
+type SelfOrArray = S | S[];
+type OptionalPick = Pick>;
+
+export type { NextFunction };
+
+/**
+ * The object returned from `.find` call by standard database adapters
+ */
+export interface Paginated {
+ total: number;
+ limit: number;
+ skip: number;
+ data: T[];
+}
+
+/**
+ * Options that can be passed when registering a service via `app.use(name, service, options)`
+ */
+export interface ServiceOptions {
+ events?: string[] | readonly string[];
+ methods?: string[] | readonly string[];
+ serviceEvents?: string[] | readonly string[];
+ routeParams?: { [key: string]: any };
+}
+
+export interface ClientService<
+ Result = any,
+ Data = Partial,
+ PatchData = Data,
+ FindResult = Paginated,
+ P = Params
+> {
+ find(params?: P): Promise;
+
+ get(id: Id, params?: P): Promise;
+
+ create(data: Data[], params?: P): Promise;
+ create(data: Data, params?: P): Promise;
+
+ update(id: Id, data: Data, params?: P): Promise;
+ update(id: NullableId, data: Data, params?: P): Promise;
+ update(id: null, data: Data, params?: P): Promise;
+
+ patch(
+ id: NullableId,
+ data: PatchData,
+ params?: P
+ ): Promise;
+ patch(id: Id, data: PatchData, params?: P): Promise;
+ patch(id: null, data: PatchData, params?: P): Promise;
+
+ remove(id: NullableId, params?: P): Promise;
+ remove(id: Id, params?: P): Promise;
+ remove(id: null, params?: P): Promise;
+}
+
+export interface ServiceMethods, P = Params> {
+ find(params?: P): Promise;
+
+ get(id: Id, params?: P): Promise;
+
+ create(data: D, params?: P): Promise;
+
+ update(id: NullableId, data: D, params?: P): Promise;
+
+ patch(id: NullableId, data: D, params?: P): Promise;
+
+ remove(id: NullableId, params?: P): Promise;
+
+ setup?(app: Application, path: string): Promise;
+
+ teardown?(app: Application, path: string): Promise;
+}
+
+export interface ServiceOverloads, P = Params> {
+ create?(data: D[], params?: P): Promise;
+
+ update?(id: Id, data: D, params?: P): Promise;
+
+ update?(id: null, data: D, params?: P): Promise;
+
+ patch?(id: Id, data: D, params?: P): Promise;
+
+ patch?(id: null, data: D, params?: P): Promise;
+
+ remove?(id: Id, params?: P): Promise;
+
+ remove?(id: null, params?: P): Promise;
+}
+
+export type Service, P = Params> = ServiceMethods<
+ T,
+ D,
+ P
+> &
+ ServiceOverloads;
+
+export type ServiceInterface, P = Params> = Partial<
+ ServiceMethods
+>;
+
+export interface ServiceAddons
+ extends EventEmitter {
+ id?: string;
+ hooks(options: HookOptions): this;
+}
+
+export interface ServiceHookOverloads {
+ find(params: P, context: HookContext): Promise;
+
+ get(id: Id, params: P, context: HookContext): Promise;
+
+ create(
+ data: ServiceGenericData | ServiceGenericData[],
+ params: P,
+ context: HookContext
+ ): Promise;
+
+ update(
+ id: NullableId,
+ data: ServiceGenericData,
+ params: P,
+ context: HookContext
+ ): Promise;
+
+ patch(
+ id: NullableId,
+ data: ServiceGenericData,
+ params: P,
+ context: HookContext
+ ): Promise;
+
+ remove(id: NullableId, params: P, context: HookContext): Promise;
+}
+
+export type FeathersService = S &
+ ServiceAddons &
+ OptionalPick, keyof S>;
+
+export type CustomMethods = {
+ [K in keyof T]: (data: T[K][0], params?: Params) => Promise;
+};
+
+/**
+ * An interface usually use by transport clients that represents a e.g. HTTP or websocket
+ * connection that can be configured on the application.
+ */
+export type TransportConnection = {
+ (app: Application): void;
+ Service: any;
+ service: (
+ name: L
+ ) => keyof any extends keyof Services ? ServiceInterface : Services[L];
+};
+
+/**
+ * The interface for a custom service method. Can e.g. be used to type client side services.
+ */
+export type CustomMethod = (
+ data: T,
+ params?: P
+) => Promise;
+
+export type ServiceMixin = (
+ service: FeathersService,
+ path: string,
+ options: ServiceOptions
+) => void;
+
+export type ServiceGenericType = S extends ServiceInterface
+ ? T
+ : any;
+export type ServiceGenericData = S extends ServiceInterface<
+ infer _T,
+ infer D
+>
+ ? D
+ : any;
+export type ServiceGenericParams = S extends ServiceInterface<
+ infer _T,
+ infer _D,
+ infer P
+>
+ ? P
+ : any;
+
+export interface FeathersApplication {
+ /**
+ * The Feathers application version
+ */
+ version: string;
+
+ /**
+ * A list of callbacks that run when a new service is registered
+ */
+ mixins: ServiceMixin>[];
+
+ /**
+ * The index of all services keyed by their path.
+ *
+ * __Important:__ Services should always be retrieved via `app.service('name')`
+ * not via `app.services`.
+ */
+ services: Services;
+
+ /**
+ * The application settings that can be used via
+ * `app.get` and `app.set`
+ */
+ settings: Settings;
+
+ /**
+ * A private-ish indicator if `app.setup()` has been called already
+ */
+ _isSetup: boolean;
+
+ /**
+ * Retrieve an application setting by name
+ *
+ * @param name The setting name
+ */
+ get(name: L): Settings[L];
+
+ /**
+ * Set an application setting
+ *
+ * @param name The setting name
+ * @param value The setting value
+ */
+ set(name: L, value: Settings[L]): this;
+
+ /**
+ * Runs a callback configure function with the current application instance.
+ *
+ * @param callback The callback `(app: Application) => {}` to run
+ */
+ configure(callback: (this: this, app: this) => void): this;
+
+ /**
+ * Returns a fallback service instance that will be registered
+ * when no service was found. Usually throws a `NotFound` error
+ * but also used to instantiate client side services.
+ *
+ * @param location The path of the service
+ */
+ defaultService(location: string): ServiceInterface;
+
+ /**
+ * Register a new service or a sub-app. When passed another
+ * Feathers application, all its services will be re-registered
+ * with the `path` prefix.
+ *
+ * @param path The path for the service to register
+ * @param service The service object to register or another
+ * Feathers application to use a sub-app under the `path` prefix.
+ * @param options The options for this service
+ */
+ use(
+ path: L,
+ service: keyof any extends keyof Services
+ ? ServiceInterface | Application
+ : Services[L],
+ options?: ServiceOptions
+ ): this;
+
+ /**
+ * Unregister an existing service.
+ *
+ * @param path The name of the service to unregister
+ */
+ unuse(
+ path: L
+ ): Promise<
+ FeathersService<
+ this,
+ keyof any extends keyof Services ? Service : Services[L]
+ >
+ >;
+
+ /**
+ * Get the Feathers service instance for a path. This will
+ * be the service originally registered with Feathers functionality
+ * like hooks and events added.
+ *
+ * @param path The name of the service.
+ */
+ service(
+ path: L
+ ): FeathersService<
+ this,
+ keyof any extends keyof Services ? Service : Services[L]
+ >;
+
+ /**
+ * Set up the application and call all services `.setup` method if available.
+ *
+ * @param server A server instance (optional)
+ */
+ setup(server?: any): Promise;
+
+ /**
+ * Tear down the application and call all services `.teardown` method if available.
+ *
+ * @param server A server instance (optional)
+ */
+ teardown(server?: any): Promise;
+
+ /**
+ * Register application level hooks.
+ *
+ * @param map The application hook settings.
+ */
+ hooks(map: ApplicationHookOptions): this;
+}
+
+// This needs to be an interface instead of a type
+// so that the declaration can be extended by other modules
+export interface Application
+ extends FeathersApplication,
+ EventEmitter {}
+
+export type Id = number | string;
+export type NullableId = Id | null;
+
+export interface Query {
+ [key: string]: any;
+}
+
+export interface Params {
+ query?: Q;
+ provider?: string;
+ route?: { [key: string]: any };
+ headers?: { [key: string]: any };
+}
+
+export interface Http {
+ /**
+ * A writeable, optional property with status code override.
+ */
+ status?: number;
+ /**
+ * A writeable, optional property with headers.
+ */
+ headers?: { [key: string]: string | string[] };
+ /**
+ * A writeable, optional property with `Location` header's value.
+ */
+ location?: string;
+}
+
+export interface HookContext
+ extends BaseHookContext> {
+ /**
+ * A read only property that contains the Feathers application object. This can be used to
+ * retrieve other services (via context.app.service('name')) or configuration values.
+ */
+ readonly app: A;
+ /**
+ * A read only property with the name of the service method (one of find, get,
+ * create, update, patch, remove).
+ */
+ readonly method: string;
+ /**
+ * A read only property and contains the service name (or path) without leading or
+ * trailing slashes.
+ */
+ readonly path: string;
+ /**
+ * A read only property and contains the service this hook currently runs on.
+ */
+ readonly service: S;
+ /**
+ * A read only property with the hook type (one of before, after or error).
+ * Will be `null` for asynchronous hooks.
+ */
+ readonly type: null | "before" | "after" | "error";
+ /**
+ * The list of method arguments. Should not be modified, modify the
+ * `params`, `data` and `id` properties instead.
+ */
+ readonly arguments: any[];
+ /**
+ * A writeable property containing the data of a create, update and patch service
+ * method call.
+ */
+ data?: ServiceGenericData;
+ /**
+ * A writeable property with the error object that was thrown in a failed method call.
+ * It is only available in error hooks.
+ */
+ error?: any;
+ /**
+ * 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.
+ */
+ id?: Id;
+ /**
+ * A writeable property that contains the service method parameters (including
+ * params.query).
+ */
+ params: ServiceGenericParams;
+ /**
+ * 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
+ *
+ * - A before hook to skip the actual service method (database) call
+ * - An error hook to swallow the error and return a result instead
+ */
+ result?: ServiceGenericType;
+ /**
+ * 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.
+ */
+ dispatch?: ServiceGenericType;
+ /**
+ * A writeable, optional property that allows to override the standard HTTP status
+ * code that should be returned.
+ *
+ * @deprecated Use `http.status` instead.
+ */
+ statusCode?: number;
+ /**
+ * A writeable, optional property with options specific to HTTP transports.
+ */
+ http?: Http;
+ /**
+ * The event emitted by this method. Can be set to `null` to skip event emitting.
+ */
+ event: string | null;
+}
+
+// Regular hook typings
+export type HookFunction = (
+ this: S,
+ context: HookContext
+) =>
+ | Promise | void>
+ | HookContext
+ | void;
+
+export type Hook = HookFunction;
+
+type HookMethodMap = {
+ [L in keyof S]?: SelfOrArray