Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c38617df77 | |||
| 61c387113f | |||
| 7b6e7c3018 | |||
| 015b51a598 | |||
| f4417a2a58 | |||
| 0faf1ac6ba | |||
| 2f53b7f101 | |||
| 753d4c8a6e | |||
| d8182a9580 | |||
| 2630d0b401 | |||
| 151d51f6e8 | |||
| b970d3c454 | |||
| 19512cb6b2 | |||
| a228eaa04d | |||
| a592182e1c | |||
| 7970865f2a | |||
| dc92f7c24b | |||
| 384235bed9 | |||
| 4987a48fec | |||
| 619b76efcf | |||
| da427d5542 | |||
| c9d101b99a | |||
| 21cfccbfac | |||
| f91748e8d7 | |||
| 7e2f480a6c | |||
| 71c5140462 | |||
| aa8be3e99d | |||
| 2940dcff42 | |||
| accd28fc19 | |||
| 660baabe33 | |||
| 315c31389d | |||
| 34336f9ece | |||
| 4e30667a14 | |||
| 8e01a115ba | |||
| c3138c7001 | |||
| 6f8e30598c | |||
| 024c546345 | |||
| ce6fcb3fe6 | |||
| a37735daa5 | |||
| f0591c0aa2 | |||
| 06d70f250e | |||
| bf915d7215 | |||
| 92bc6a5932 | |||
| d304a20ba2 | |||
| 0734e360f6 | |||
| 70e79bfbf5 | |||
| 2c51549ef7 | |||
| a6933cdb66 | |||
| 927726fae6 | |||
| 62f86064dc | |||
| 0610835df7 | |||
| 883a9da071 | |||
| e541af8201 | |||
| 1fa908d859 | |||
| 39aa1b430e | |||
| 29cb45392f | |||
| 441c897442 | |||
| 5baa304add | |||
| c160171ec9 | |||
| e229c69421 | |||
| 8ab911f4dd | |||
| b767ff94ff | |||
| 05d4e1f117 | |||
| 492a9fc70b | |||
| 4faf126fa3 | |||
| ce0a7c3d6d | |||
| db56bc097d | |||
| d61bb4da4f | |||
| 1b7eec07be | |||
| ea3798f1ec | |||
| a78c36250b | |||
| bfcfd90bf5 | |||
| b6e3fd9a55 | |||
| e67951c0c1 | |||
| e9280799c9 | |||
| 3f036a1faa | |||
| 841eb0ef30 | |||
| 4305ee261c | |||
| de5ed10fcf | |||
| 0d327b14ec | |||
| 985c4d5b3f | |||
| bbed27395a | |||
| e3ca73d34f | |||
| fb20387229 | |||
| 068b3cc87e | |||
| 364081a24c | |||
| b629c232b2 | |||
| 1d2afb8f03 | |||
| 9776978f50 | |||
| 08c0686f05 | |||
| a45711f58b | |||
| 419d3880d2 | |||
| ad85560e70 | |||
| 8e4f74dc0d | |||
| 48b88f2989 | |||
| 2c6f91d225 | |||
| 26ba4f1678 | |||
| de80521bfa | |||
| 29414d8e33 | |||
| 1d9238c5d6 | |||
| 1ae2c62237 | |||
| f17372e08d | |||
| 50d5f68848 | |||
| 67400160a4 | |||
| d7e0132e23 | |||
| e9e6625df5 | |||
| ecf949e05a | |||
| eb3f046325 | |||
| d40772caf7 | |||
| a06db8d24b | |||
| 67f82cfb51 | |||
| 01b93675d8 | |||
| 93262362a3 | |||
| 50d550a350 | |||
| d880a87225 | |||
| c9e5f39b7a | |||
| 16565770ea | |||
| 9e927b6aac | |||
| be65185b76 | |||
| 956bd7878c | |||
| 42d0681ff3 | |||
| a7f8fbae9a | |||
| f64c30f3f3 | |||
| 8cd72c6359 | |||
| b1cda614c3 | |||
| 94730ccee8 | |||
| a8107594a8 | |||
| 385679b4a4 | |||
| 563f1ce2eb | |||
| 8f3500295f | |||
| 8be0b8e07f | |||
| 2f6f9b4f13 | |||
| 81c8820b80 | |||
| 94ba867b00 | |||
| ae4ccedcc2 | |||
| 05ec76bf91 | |||
| 6923ead0e6 | |||
| 9b0d0e06e4 | |||
| e7396ee638 | |||
| 766bd54a10 | |||
| e4950fdfec | |||
| 6c154c0773 | |||
| bd1a290007 | |||
| 734182fedf | |||
| 54f9852313 | |||
| 8f3626ce47 | |||
| 2805cad639 | |||
| 254afbda73 | |||
| cddb5a39c5 | |||
| 9ab2eca760 | |||
| db6f22584c | |||
| b79df5fa2d | |||
| 672b5e2a1a | |||
| a8095edd6b | |||
| 1b84662e46 | |||
| 255aaa2652 | |||
| c3e2a19938 | |||
| 7c25ebdd65 | |||
| a1eff91095 | |||
| 7ace51e44f | |||
| d89b0e9afd | |||
| 1212ed8d04 | |||
| b2786ee424 | |||
| b10d7ee06b | |||
| fe931e4f40 | |||
| 17eaef1d9b | |||
| 2c4da47c7f | |||
| 92b9aa69d5 | |||
| fe8383adc8 | |||
| 40f5d48edf | |||
| 38262bdbb9 | |||
| 18b2dc3f80 | |||
| 8ad83a4fc6 | |||
| 5e99a3a354 | |||
| cbe2c251fb | |||
| ce94951550 | |||
| f1969bc88c | |||
| 7be078995e | |||
| f8b9bbd403 | |||
| 656eef7bcd | |||
| 6326ec8211 | |||
| 512eb9328b | |||
| 8f4c8cd88f | |||
| 0f312478bc | |||
| b022822a97 | |||
| ee396004a5 | |||
| 2077acddcb | |||
| e34cfec074 | |||
| 595733435b | |||
| e610d9dff0 | |||
| f5b28b0dc0 | |||
| c8f8c6c7b5 | |||
| 6ce30d8063 | |||
| c489613d12 | |||
| e835aac336 |
+1
-6
@@ -7,12 +7,7 @@ module.exports = {
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser',
|
||||
},
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/essential',
|
||||
'prettier/vue',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
extends: ['plugin:@typescript-eslint/recommended', 'plugin:vue/essential', 'prettier'],
|
||||
plugins: ['@typescript-eslint', 'vue'],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Test
|
||||
name: Build
|
||||
|
||||
on: [push]
|
||||
|
||||
@@ -10,37 +10,35 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '12.x'
|
||||
node-version: '16.x'
|
||||
always-auth: true
|
||||
registry-url: https://registry.npmjs.org
|
||||
- id: cache_npm
|
||||
name: Cache Node.js modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
./node_modules.tar.zstd
|
||||
key: ${{ runner.OS }}-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
key: ${{ runner.OS }}-node16.x-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-npm-
|
||||
${{ runner.OS }}-
|
||||
${{ runner.OS }}-node16.x-
|
||||
- name: Install dependencies with NPM
|
||||
if: steps.cache_npm.outputs.cache-hit != 'true'
|
||||
run: npm ci
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
- name: Archive node_modules
|
||||
if: steps.cache_npm.outputs.cache-hit != 'true'
|
||||
run: tar --use-compress-program "zstd -T0 --long=31 -1" -cf node_modules.tar.zstd -P node_modules
|
||||
- name: Persisting node_modules artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: node_modules.tar.zstd
|
||||
path: node_modules.tar.zstd
|
||||
retention-days: 2
|
||||
|
||||
#
|
||||
# lint job
|
||||
@@ -51,22 +49,32 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
node-version: '12.x'
|
||||
token: ${{ secrets.BUILD_USER_TOKEN || github.token }} # allows commit of any fixes to trigger a new workflow run
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
always-auth: true
|
||||
registry-url: https://registry.npmjs.org
|
||||
- name: Restore node_modules artifact
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: node_modules.tar.zstd
|
||||
- name: Unarchive node_modules
|
||||
run: tar --use-compress-program "zstd -d --long=31" -xf node_modules.tar.zstd
|
||||
# ESLint
|
||||
- name: Lint source code
|
||||
run: npm run lint
|
||||
# Lint
|
||||
- name: Run linters
|
||||
uses: wearerequired/lint-action@v2
|
||||
with:
|
||||
prettier: true
|
||||
eslint: true
|
||||
eslint_args: "--ext '.ts,.js' --ignore-path '.gitignore' --ignore-pattern '.github/*'"
|
||||
continue_on_error: false
|
||||
auto_fix: ${{ secrets.BUILD_USER_TOKEN && 'true' || 'false' }}
|
||||
git_name: equabot
|
||||
git_email: git@equalogic.com
|
||||
|
||||
#
|
||||
# build job
|
||||
@@ -77,15 +85,15 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '12.x'
|
||||
node-version: '16.x'
|
||||
always-auth: true
|
||||
registry-url: https://registry.npmjs.org
|
||||
- name: Restore node_modules artifact
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: node_modules.tar.zstd
|
||||
- name: Unarchive node_modules
|
||||
@@ -113,9 +121,15 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
always-auth: true
|
||||
registry-url: https://registry.npmjs.org
|
||||
- name: Restore node_modules artifact
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: node_modules.tar.zstd
|
||||
- name: Unarchive node_modules
|
||||
@@ -125,9 +139,3 @@ jobs:
|
||||
run: node_modules/.bin/dotenv -e .env.ci -- npm run test:ci
|
||||
env:
|
||||
CI: true
|
||||
- if: always()
|
||||
name: Persisting test-results.html artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: test-results.html
|
||||
path: test/.results/test-results.html
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Cleanup
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *' # every day at 1am
|
||||
|
||||
jobs:
|
||||
remove-old-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Remove old artifacts
|
||||
uses: c-hive/gha-remove-artifacts@v1
|
||||
with:
|
||||
age: '1 days' # delete artifacts older than this
|
||||
skip-tags: false # don't treat artifacts created by runs on tagged commits any differently
|
||||
skip-recent: 2 # keep the last 2 runs, regardless of age
|
||||
@@ -3,6 +3,7 @@ name: Publish
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
#
|
||||
@@ -12,30 +13,27 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '12.x'
|
||||
node-version: '16.x'
|
||||
always-auth: true
|
||||
registry-url: https://registry.npmjs.org
|
||||
# Dependencies
|
||||
- id: cache_npm
|
||||
name: Cache Node.js modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
./node_modules.tar.zstd
|
||||
key: ${{ runner.OS }}-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
key: ${{ runner.OS }}-node16.x-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-npm-
|
||||
${{ runner.OS }}-
|
||||
${{ runner.OS }}-node16.x-
|
||||
- name: Install dependencies with NPM
|
||||
if: steps.cache_npm.outputs.cache-hit != 'true'
|
||||
run: npm ci
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
- name: Unarchive node_modules
|
||||
if: steps.cache_npm.outputs.cache-hit == 'true'
|
||||
run: tar --use-compress-program "zstd -d --long=31" -xf node_modules.tar.zstd
|
||||
@@ -56,6 +54,6 @@ jobs:
|
||||
- name: Copy extra files into dist directory
|
||||
run: cp package.json README* dist/
|
||||
- name: Publish release to NPM registry
|
||||
run: npm publish dist
|
||||
run: npm publish dist/
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISHING }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Ignore workflows
|
||||
.github
|
||||
|
||||
# Node modules
|
||||
node_modules
|
||||
|
||||
# Test results
|
||||
test/.results
|
||||
test/.coverage
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
@@ -29,7 +29,7 @@ accepted by the generated function are fully type-checked based on the query def
|
||||
type arguments at every usage.
|
||||
|
||||
Using the [`@graphql-codegen/typescript-vue-apollo-smart-ops` plugin](https://www.graphql-code-generator.com/docs/plugins/typescript-vue-apollo-smart-ops)
|
||||
you can automatically generate options functions for all of the query operations in your project.
|
||||
you can automatically generate options functions for all the query operations in your project.
|
||||
|
||||
The following example manually creates an options function and assigns it to the variable `useTodoListQuery`:
|
||||
|
||||
@@ -60,8 +60,8 @@ following example adds a `todos` Smart Query to a component, in Vue class compon
|
||||
skip: 0,
|
||||
};
|
||||
},
|
||||
})
|
||||
}
|
||||
}),
|
||||
},
|
||||
})
|
||||
class TodoList extends Vue {
|
||||
todos: Todo[] | null = null;
|
||||
@@ -114,7 +114,7 @@ is that the options accepted by the generated function are fully type-checked ba
|
||||
without needing to pass type arguments at every usage.
|
||||
|
||||
Using the [`@graphql-codegen/typescript-vue-apollo-smart-ops` plugin](https://www.graphql-code-generator.com/docs/plugins/typescript-vue-apollo-smart-ops)
|
||||
you can automatically generate mutation functions for all of the mutation operations in your project.
|
||||
you can automatically generate mutation functions for all the mutation operations in your project.
|
||||
|
||||
The following example manually creates a mutation function and assigns it to the variable `todoCreateMutation`:
|
||||
|
||||
@@ -142,10 +142,15 @@ class TodoList extends Vue {
|
||||
title: 'Bake a cake',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(`Failed to create Todo!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
- `@SmartQuery()` decorator is based on the [vue-apollo-decorator](https://github.com/chanlito/vue-apollo-decorator)
|
||||
package by chanlito, with some alteration to the types.
|
||||
|
||||
+1
-6
@@ -1,11 +1,6 @@
|
||||
{
|
||||
"directory": "src/",
|
||||
"exclude": [
|
||||
"\\.(spec|e2e-spec)\\.ts$",
|
||||
"src/cli/",
|
||||
"src/database/",
|
||||
"src/testing/"
|
||||
],
|
||||
"exclude": ["\\.(spec|e2e-spec)\\.ts$", "src/cli/", "src/database/", "src/testing/"],
|
||||
"location": "all",
|
||||
"structure": "flat",
|
||||
"singleQuotes": true,
|
||||
|
||||
Generated
+12547
-4597
File diff suppressed because it is too large
Load Diff
+28
-38
@@ -1,20 +1,21 @@
|
||||
{
|
||||
"name": "vue-apollo-smart-ops",
|
||||
"version": "0.1.0-alpha.2",
|
||||
"version": "0.2.0-beta.1",
|
||||
"description": "Create TypeScript-typed operation functions for your Vue Apollo queries and mutations.",
|
||||
"author": "Madscience Ltd",
|
||||
"author": "Equalogic Ltd",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/madscience/vue-apollo-smart-ops.git"
|
||||
"url": "https://github.com/equalogic/vue-apollo-smart-ops.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist && npm run barrels:generate",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"postbuild": "cp package.json README.md dist/",
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint --ext .ts --ignore-path .gitignore .",
|
||||
"lint:fix": "eslint --ext .ts --ignore-path .gitignore . --fix",
|
||||
"test": "jest",
|
||||
@@ -35,42 +36,39 @@
|
||||
"peerDependencies": {
|
||||
"apollo-client": ">=2.6",
|
||||
"apollo-link": ">=1.2",
|
||||
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0",
|
||||
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
||||
"vue": ">=2.6",
|
||||
"vue-apollo": ">=3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.0.1",
|
||||
"@types/lodash.isplainobject": "4.0.6",
|
||||
"@types/lodash.mapvalues": "4.6.6",
|
||||
"@typescript-eslint/eslint-plugin": "4.30.0",
|
||||
"@typescript-eslint/parser": "4.30.0",
|
||||
"@vue/test-utils": "1.2.2",
|
||||
"@types/jest": "27.5.2",
|
||||
"@types/lodash.isplainobject": "4.0.7",
|
||||
"@types/lodash.mapvalues": "4.6.7",
|
||||
"@typescript-eslint/eslint-plugin": "5.30.5",
|
||||
"@typescript-eslint/parser": "5.30.5",
|
||||
"@vue/test-utils": "1.3.0",
|
||||
"apollo-client": "2.6.10",
|
||||
"apollo-link": "1.2.14",
|
||||
"barrelsby": "2.2.0",
|
||||
"dotenv-cli": "4.0.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "7.2.0",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"eslint-plugin-jest": "24.4.0",
|
||||
"barrelsby": "2.3.4",
|
||||
"dotenv-cli": "6.0.0",
|
||||
"eslint": "8.19.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-jest": "26.5.3",
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-prettier": "3.4.1",
|
||||
"eslint-plugin-promise": "4.3.1",
|
||||
"eslint-plugin-vue": "7.17.0",
|
||||
"graphql": "15.5.2",
|
||||
"graphql-tag": "2.12.5",
|
||||
"husky": "7.0.2",
|
||||
"jest": "27.1.0",
|
||||
"lint-staged": "11.1.2",
|
||||
"eslint-plugin-promise": "6.0.0",
|
||||
"eslint-plugin-vue": "9.2.0",
|
||||
"graphql": "15.8.0",
|
||||
"graphql-tag": "2.12.6",
|
||||
"jest": "27.5.1",
|
||||
"mkdirp": "1.0.4",
|
||||
"np": "7.5.0",
|
||||
"prettier": "2.2.1",
|
||||
"np": "7.6.1",
|
||||
"prettier": "2.7.1",
|
||||
"rimraf": "3.0.2",
|
||||
"ts-jest": "27.0.5",
|
||||
"typescript": "4.2.4",
|
||||
"ts-jest": "27.1.5",
|
||||
"typescript": "4.7.4",
|
||||
"vue": "2.6.14",
|
||||
"vue-apollo": "3.0.7",
|
||||
"vue-apollo": "3.1.0",
|
||||
"vue-class-component": "7.2.6",
|
||||
"vue-property-decorator": "9.1.2"
|
||||
},
|
||||
@@ -78,13 +76,5 @@
|
||||
"node": ">=12.9.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,js}": "eslint --ext .ts,.js --ignore-path .gitignore --fix --cache"
|
||||
}
|
||||
"types": "index.d.ts"
|
||||
}
|
||||
|
||||
+10
-7
@@ -2,7 +2,7 @@
|
||||
"extends": [
|
||||
"config:js-lib",
|
||||
":automergeMajor",
|
||||
":automergePr",
|
||||
":automergeBranch",
|
||||
":automergeRequireAllStatusChecks",
|
||||
":dependencyDashboard",
|
||||
":semanticCommitsDisabled"
|
||||
@@ -12,12 +12,9 @@
|
||||
"prCreation": "not-pending",
|
||||
"stabilityDays": 3,
|
||||
"rebaseWhen": "conflicted",
|
||||
"labels": [
|
||||
"dependencies"
|
||||
],
|
||||
"reviewers": [
|
||||
"sgarner"
|
||||
],
|
||||
"lockFileMaintenance": true,
|
||||
"labels": ["dependencies"],
|
||||
"reviewers": ["sgarner"],
|
||||
"packageRules": [
|
||||
{
|
||||
"packagePatterns": ["eslint"],
|
||||
@@ -26,6 +23,12 @@
|
||||
{
|
||||
"packagePatterns": ["jest"],
|
||||
"groupName": "jest"
|
||||
},
|
||||
{
|
||||
"matchDatasources": ["nvm", "npm"],
|
||||
"matchPackageNames": ["node", "@types/node"],
|
||||
"groupName": "Node.js",
|
||||
"allowedVersions": "^16"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import {
|
||||
ApolloError,
|
||||
ApolloErrorType,
|
||||
ApolloOperationContext,
|
||||
GraphQLError,
|
||||
InputValidationError,
|
||||
ProcessedApolloError,
|
||||
ServerError,
|
||||
UnauthorizedError,
|
||||
} from './types';
|
||||
|
||||
export function isApolloError(error: ApolloError | any): error is ApolloError {
|
||||
return error.graphQLErrors !== undefined;
|
||||
}
|
||||
|
||||
export function isGraphQLError(error: GraphQLError | any): error is GraphQLError {
|
||||
return error.extensions !== undefined;
|
||||
}
|
||||
|
||||
export class ApolloErrorProcessor<TApp = Vue, TContext = ApolloOperationContext> {
|
||||
public static FriendlyMessages: Record<string, string> = {
|
||||
FAILED_TO_FETCH:
|
||||
'Unable to communicate with server. The service may be down or you may be offline. Try again in a moment.',
|
||||
INTERNAL_SERVER_ERROR: `A server error has occurred.`,
|
||||
};
|
||||
|
||||
public processedErrors: ProcessedApolloError[];
|
||||
|
||||
protected readonly originalError: Error;
|
||||
protected readonly app: TApp;
|
||||
protected readonly context: TContext;
|
||||
|
||||
public constructor(error: ApolloError, app: TApp, context: TContext) {
|
||||
this.originalError = error;
|
||||
this.app = app;
|
||||
this.context = context;
|
||||
|
||||
this.processedErrors = this.processApolloError(error);
|
||||
}
|
||||
|
||||
public showErrorNotifications(): void {
|
||||
// This is just an example - to do something else (e.g. showing a visible notification to the user), you should
|
||||
// implement your own class that extends ApolloErrorProcessor and replace this showErrorNotifications method.
|
||||
this.processedErrors.forEach(error => {
|
||||
console.error(`${error.type}: ${error.message}`, error.error);
|
||||
});
|
||||
}
|
||||
|
||||
public cleanError(error: ApolloError | GraphQLError | Record<string, any>): Error {
|
||||
if (error instanceof Error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// the `error` object we have may not be an actual Error instance
|
||||
// create a new one suitable for e.g. capturing to Sentry
|
||||
const cleanError = new Error(error.message);
|
||||
|
||||
if (isGraphQLError(error)) {
|
||||
cleanError.name = 'GraphQLError' + (error.extensions?.code != null ? `[${error.extensions.code}]` : '');
|
||||
cleanError.stack = this.originalError.stack;
|
||||
|
||||
Object.defineProperty(cleanError, 'nodes', { value: error.nodes });
|
||||
Object.defineProperty(cleanError, 'source', { value: error.source });
|
||||
Object.defineProperty(cleanError, 'positions', { value: error.positions });
|
||||
Object.defineProperty(cleanError, 'path', { value: error.path });
|
||||
Object.defineProperty(cleanError, 'extensions', { value: JSON.stringify(error.extensions) });
|
||||
Object.defineProperty(cleanError, 'originalError', { value: this.originalError });
|
||||
} else {
|
||||
Object.keys(error).forEach(key => Object.defineProperty(cleanError, key, { value: error[key] }));
|
||||
}
|
||||
|
||||
return cleanError;
|
||||
}
|
||||
|
||||
protected isUnauthorizedError(error: GraphQLError): boolean {
|
||||
return (
|
||||
error.message === 'Unauthorized' ||
|
||||
error.extensions?.code === 'FORBIDDEN' ||
|
||||
error.extensions?.exception?.status === 401
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars
|
||||
protected onUnauthorizedError(error: UnauthorizedError): void {
|
||||
// extending classes can take action here, e.g. go to log in page
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars
|
||||
protected onServerError(error: ServerError): void {
|
||||
// extending classes can take action here, e.g. capture to Sentry
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars
|
||||
protected onInputValidationError(error: InputValidationError): void {
|
||||
// extending classes can take action here, e.g. capture to Sentry
|
||||
}
|
||||
|
||||
protected getFriendlyMessage(errorCode: string, errorMessage: string): string;
|
||||
protected getFriendlyMessage(errorCode: string): string | undefined;
|
||||
protected getFriendlyMessage(errorCode: string, errorMessage?: string): string | undefined {
|
||||
return (this.constructor as typeof ApolloErrorProcessor).FriendlyMessages[errorCode] ?? errorMessage;
|
||||
}
|
||||
|
||||
private processApolloError(error: ApolloError): ProcessedApolloError[] {
|
||||
if (error.graphQLErrors != null && error.graphQLErrors.length > 0) {
|
||||
// Successful request but with errors from the resolver
|
||||
return error.graphQLErrors.flatMap(graphQLError => this.processGraphQLError(graphQLError));
|
||||
}
|
||||
|
||||
if (
|
||||
error.networkError != null &&
|
||||
error.networkError.result != null &&
|
||||
error.networkError.result.errors != null &&
|
||||
error.networkError.result.errors.length > 0
|
||||
) {
|
||||
// Network error that contains GraphQL errors inside it. Can occur when server responds with a non-200 status code
|
||||
return error.networkError.result.errors.flatMap(graphQLError => this.processGraphQLError(graphQLError));
|
||||
}
|
||||
|
||||
if (error.networkError != null) {
|
||||
// Network error, e.g. server is not responding or some other exception occurs
|
||||
return this.processNetworkError(error);
|
||||
}
|
||||
|
||||
// Some other internal server error
|
||||
const processedError: ServerError = {
|
||||
type: ApolloErrorType.SERVER_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
};
|
||||
|
||||
this.onServerError(processedError);
|
||||
|
||||
return [processedError];
|
||||
}
|
||||
|
||||
private processGraphQLError(error: GraphQLError): ProcessedApolloError[] {
|
||||
if (this.isUnauthorizedError(error)) {
|
||||
// Unauthorized (not logged in, or not allowed) error
|
||||
const processedError: UnauthorizedError = {
|
||||
type: ApolloErrorType.UNAUTHORIZED_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
path: error.path,
|
||||
};
|
||||
|
||||
this.onUnauthorizedError(processedError);
|
||||
|
||||
return [processedError];
|
||||
}
|
||||
|
||||
if (error.extensions?.validationErrors != null) {
|
||||
// User input validation error
|
||||
const processedError: InputValidationError = {
|
||||
type: ApolloErrorType.INPUT_VALIDATION_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
path: error.path,
|
||||
invalidArgs: error.extensions.invalidArgs,
|
||||
violations: error.extensions.validationErrors,
|
||||
};
|
||||
|
||||
this.onInputValidationError(processedError);
|
||||
|
||||
return [processedError];
|
||||
}
|
||||
|
||||
// Other GraphQL resolver error - probably a bug
|
||||
const processedError: ServerError = {
|
||||
type: error.extensions?.code != null ? error.extensions.code : ApolloErrorType.SERVER_ERROR,
|
||||
error,
|
||||
path: error.path,
|
||||
message: this.getFriendlyMessage('INTERNAL_SERVER_ERROR', error.message),
|
||||
};
|
||||
|
||||
this.onServerError(processedError);
|
||||
|
||||
return [processedError];
|
||||
}
|
||||
|
||||
private processNetworkError(error: ApolloError): ProcessedApolloError[] {
|
||||
const errors: ProcessedApolloError[] = [];
|
||||
let message: string;
|
||||
|
||||
if (error.networkError != null && error.networkError.message != null) {
|
||||
message = this.processErrorMessage(error.networkError.message);
|
||||
} else {
|
||||
message = this.processErrorMessage(error.message);
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case 'Failed to fetch':
|
||||
message = this.getFriendlyMessage('FAILED_TO_FETCH', message);
|
||||
break;
|
||||
}
|
||||
|
||||
errors.push({
|
||||
type: ApolloErrorType.NETWORK_ERROR,
|
||||
error,
|
||||
statusCode: error.networkError != null ? error.networkError.statusCode : undefined,
|
||||
message,
|
||||
});
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
private processErrorMessage(message: GraphQLError['message']): string {
|
||||
if (typeof message === 'object') {
|
||||
if (message.error != null) {
|
||||
return message.error;
|
||||
}
|
||||
|
||||
return 'Unknown error: ' + JSON.stringify(message);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
ApolloErrorType,
|
||||
InputValidationError,
|
||||
NetworkError,
|
||||
ProcessedApolloError,
|
||||
ServerError,
|
||||
UnauthorizedError,
|
||||
UserInputError,
|
||||
ValidationRuleViolation,
|
||||
} from './types';
|
||||
|
||||
export interface ApolloErrorHandlerResultInterface {
|
||||
allErrors: ProcessedApolloError[];
|
||||
validationRuleViolations?: ValidationRuleViolation[];
|
||||
}
|
||||
|
||||
export class ApolloErrorHandlerResult implements ApolloErrorHandlerResultInterface {
|
||||
public readonly allErrors: ProcessedApolloError[];
|
||||
|
||||
public constructor(
|
||||
public readonly unhandledErrors: ProcessedApolloError[],
|
||||
public readonly handledErrors: ProcessedApolloError[],
|
||||
) {
|
||||
this.allErrors = [...unhandledErrors, ...handledErrors];
|
||||
}
|
||||
|
||||
public get networkErrors(): NetworkError[] {
|
||||
return this.allErrors.filter((e): e is NetworkError => e.type === ApolloErrorType.NETWORK_ERROR);
|
||||
}
|
||||
|
||||
public get serverErrors(): ServerError[] {
|
||||
return this.allErrors.filter((e): e is ServerError => e.type === ApolloErrorType.SERVER_ERROR);
|
||||
}
|
||||
|
||||
public get unauthorizedErrors(): UnauthorizedError[] {
|
||||
return this.allErrors.filter((e): e is UnauthorizedError => e.type === ApolloErrorType.UNAUTHORIZED_ERROR);
|
||||
}
|
||||
|
||||
public get userInputErrors(): UserInputError[] {
|
||||
return this.allErrors.filter((e): e is UserInputError => e.type === ApolloErrorType.BAD_USER_INPUT);
|
||||
}
|
||||
|
||||
public get inputValidationErrors(): InputValidationError[] {
|
||||
return this.allErrors.filter((e): e is InputValidationError => e.type === ApolloErrorType.INPUT_VALIDATION_ERROR);
|
||||
}
|
||||
|
||||
public get validationRuleViolations(): ValidationRuleViolation[] {
|
||||
return this.inputValidationErrors.flatMap(e => e.violations);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { processApolloError } from './processApolloError';
|
||||
import { ApolloOperationContext } from '../types';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import { ApolloError, ApolloOperationErrorHandlerFunction } from './types';
|
||||
import { ApolloErrorHandlerResult } from './ApolloErrorHandlerResult';
|
||||
|
||||
/**
|
||||
* This is a simple example of an error handler function. You can copy this and implement your own in your application.
|
||||
*/
|
||||
export const handleApolloError: ApolloOperationErrorHandlerFunction<
|
||||
ApolloError,
|
||||
Vue,
|
||||
ApolloOperationContext,
|
||||
ApolloErrorHandlerResult
|
||||
> = (error: ApolloError, app: Vue, context?: ApolloOperationContext): ApolloErrorHandlerResult => {
|
||||
const { unhandledErrors, handledErrors } = processApolloError(error, {
|
||||
app,
|
||||
context,
|
||||
// Example of a handler function for a particular type of error:
|
||||
onUnauthorizedError: error => {
|
||||
console.warn('Unauthorized! Logging you out...', error);
|
||||
//logout();
|
||||
|
||||
// Returning true indicates to the processor that we've handled this error
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
unhandledErrors.forEach(error => {
|
||||
console.error(`${error.type}: ${error.message}`, error.error);
|
||||
});
|
||||
|
||||
return new ApolloErrorHandlerResult(unhandledErrors, handledErrors);
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from './ApolloErrorHandlerResult';
|
||||
export * from './handleApolloError';
|
||||
export * from './processApolloError';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,213 @@
|
||||
import Vue from 'vue';
|
||||
import { ApolloOperationContext } from '../types';
|
||||
import {
|
||||
ApolloError,
|
||||
ApolloErrorType,
|
||||
GraphQLError,
|
||||
InputValidationError,
|
||||
NetworkError,
|
||||
ProcessedApolloError,
|
||||
ServerError,
|
||||
UnauthorizedError,
|
||||
} from './types';
|
||||
|
||||
export function isApolloError(error: ApolloError | any): error is ApolloError {
|
||||
return error.graphQLErrors !== undefined;
|
||||
}
|
||||
|
||||
export function isGraphQLError(error: GraphQLError | any): error is GraphQLError {
|
||||
return error.extensions !== undefined;
|
||||
}
|
||||
|
||||
function normalizeErrorMessage(message: GraphQLError['message']): string {
|
||||
if (typeof message === 'object') {
|
||||
if (message.error != null) {
|
||||
return message.error;
|
||||
}
|
||||
|
||||
return 'Unknown error: ' + JSON.stringify(message);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function normalizeError(error: GraphQLError | Error): Error {
|
||||
if (isGraphQLError(error)) {
|
||||
return {
|
||||
...error,
|
||||
message: normalizeErrorMessage(error.message),
|
||||
};
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
function translateErrorMessage(messageOrCode: string, translations: Record<string, string>): string {
|
||||
return translations[messageOrCode] ?? messageOrCode;
|
||||
}
|
||||
|
||||
export interface ApolloErrorProcessorOptions<TApp = Vue, TContext = ApolloOperationContext> {
|
||||
app?: TApp;
|
||||
context?: TContext;
|
||||
isUnauthorizedError?: (error: GraphQLError) => boolean;
|
||||
onUnauthorizedError?: (error: UnauthorizedError) => boolean | void;
|
||||
onInputValidationError?: (error: InputValidationError) => boolean | void;
|
||||
onServerError?: (error: ServerError) => boolean | void;
|
||||
onNetworkError?: (error: NetworkError) => boolean | void;
|
||||
translations?: Record<string, string>;
|
||||
}
|
||||
|
||||
export const defaultErrorMessageTranslations: Record<string, string> = {
|
||||
FAILED_TO_FETCH:
|
||||
'Unable to communicate with server. The service may be down or you may be offline. Try again in a moment.',
|
||||
INTERNAL_SERVER_ERROR: `A server error has occurred.`,
|
||||
};
|
||||
|
||||
const defaultProcessorOptions: ApolloErrorProcessorOptions = {
|
||||
isUnauthorizedError: (error: GraphQLError) =>
|
||||
error.message === 'Unauthorized' ||
|
||||
error.extensions?.code === 'FORBIDDEN' ||
|
||||
error.extensions?.exception?.status === 401,
|
||||
translations: defaultErrorMessageTranslations,
|
||||
};
|
||||
|
||||
export interface ApolloErrorProcessorResult {
|
||||
unhandledErrors: ProcessedApolloError[];
|
||||
handledErrors: ProcessedApolloError[];
|
||||
}
|
||||
|
||||
function processGraphQLError(
|
||||
error: GraphQLError,
|
||||
options: ApolloErrorProcessorOptions = {},
|
||||
): ApolloErrorProcessorResult {
|
||||
options = { ...defaultProcessorOptions, ...options };
|
||||
const { isUnauthorizedError, onUnauthorizedError, onInputValidationError, onServerError, translations } = options;
|
||||
|
||||
if (isUnauthorizedError != null && isUnauthorizedError(error)) {
|
||||
// Unauthorized (not logged in, or not allowed) error
|
||||
const processedError: UnauthorizedError = {
|
||||
type: ApolloErrorType.UNAUTHORIZED_ERROR,
|
||||
error: normalizeError(error),
|
||||
message: normalizeErrorMessage(error.message),
|
||||
path: error.path,
|
||||
};
|
||||
|
||||
if (onUnauthorizedError != null && onUnauthorizedError(processedError)) {
|
||||
return { unhandledErrors: [], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
return { unhandledErrors: [processedError], handledErrors: [] };
|
||||
}
|
||||
|
||||
if (error.extensions?.validationErrors != null) {
|
||||
// User input validation error
|
||||
const processedError: InputValidationError = {
|
||||
type: ApolloErrorType.INPUT_VALIDATION_ERROR,
|
||||
error: normalizeError(error),
|
||||
message: normalizeErrorMessage(error.message),
|
||||
path: error.path,
|
||||
invalidArgs: error.extensions.invalidArgs,
|
||||
violations: error.extensions.validationErrors,
|
||||
};
|
||||
|
||||
if (onInputValidationError != null && onInputValidationError(processedError)) {
|
||||
return { unhandledErrors: [], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
return { unhandledErrors: [processedError], handledErrors: [] };
|
||||
}
|
||||
|
||||
// Other GraphQL resolver error - probably a bug
|
||||
const processedError: ServerError = {
|
||||
type: error.extensions?.code != null ? error.extensions.code : ApolloErrorType.SERVER_ERROR,
|
||||
error: normalizeError(error),
|
||||
message: translateErrorMessage('INTERNAL_SERVER_ERROR', translations ?? defaultErrorMessageTranslations),
|
||||
path: error.path,
|
||||
};
|
||||
|
||||
if (onServerError != null && onServerError(processedError)) {
|
||||
return { unhandledErrors: [], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
return { unhandledErrors: [processedError], handledErrors: [] };
|
||||
}
|
||||
|
||||
function processNetworkError(
|
||||
error: ApolloError,
|
||||
options: ApolloErrorProcessorOptions = {},
|
||||
): ApolloErrorProcessorResult {
|
||||
options = { ...defaultProcessorOptions, ...options };
|
||||
const { onNetworkError, translations } = options;
|
||||
|
||||
let message: string =
|
||||
error.networkError != null && error.networkError.message != null
|
||||
? normalizeErrorMessage(error.networkError.message)
|
||||
: normalizeErrorMessage(error.message);
|
||||
|
||||
switch (message) {
|
||||
case 'Failed to fetch':
|
||||
message = translateErrorMessage('FAILED_TO_FETCH', translations ?? defaultErrorMessageTranslations);
|
||||
break;
|
||||
}
|
||||
|
||||
const processedError: NetworkError = {
|
||||
type: ApolloErrorType.NETWORK_ERROR,
|
||||
error,
|
||||
statusCode: error.networkError != null ? error.networkError.statusCode : undefined,
|
||||
message,
|
||||
};
|
||||
|
||||
if (onNetworkError != null && onNetworkError(processedError)) {
|
||||
return { unhandledErrors: [], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
return { unhandledErrors: [processedError], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
export function processApolloError(
|
||||
error: ApolloError,
|
||||
options: ApolloErrorProcessorOptions = {},
|
||||
): ApolloErrorProcessorResult {
|
||||
options = { ...defaultProcessorOptions, ...options };
|
||||
const { onServerError } = options;
|
||||
|
||||
if (error.graphQLErrors != null && error.graphQLErrors.length > 0) {
|
||||
// Successful request but with errors from the resolver
|
||||
const errorProcessorResults = error.graphQLErrors.map(graphQLError => processGraphQLError(graphQLError, options));
|
||||
|
||||
return {
|
||||
unhandledErrors: errorProcessorResults.flatMap(result => result.unhandledErrors),
|
||||
handledErrors: errorProcessorResults.flatMap(result => result.handledErrors),
|
||||
};
|
||||
}
|
||||
|
||||
if (error.networkError?.result?.errors != null && error.networkError.result.errors.length > 0) {
|
||||
// Network error that contains GraphQL errors inside it. Can occur when server responds with a non-200 status code
|
||||
const errorProcessorResults = error.networkError.result.errors.map(graphQLError =>
|
||||
processGraphQLError(graphQLError, options),
|
||||
);
|
||||
|
||||
return {
|
||||
unhandledErrors: errorProcessorResults.flatMap(result => result.unhandledErrors),
|
||||
handledErrors: errorProcessorResults.flatMap(result => result.handledErrors),
|
||||
};
|
||||
}
|
||||
|
||||
if (error.networkError != null) {
|
||||
// Network error, e.g. server is not responding or some other exception occurs
|
||||
return processNetworkError(error, options);
|
||||
}
|
||||
|
||||
// Some other internal server error
|
||||
const processedError: ServerError = {
|
||||
type: ApolloErrorType.SERVER_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
};
|
||||
|
||||
if (onServerError != null && onServerError(processedError)) {
|
||||
return { unhandledErrors: [], handledErrors: [processedError] };
|
||||
}
|
||||
|
||||
return { unhandledErrors: [processedError], handledErrors: [] };
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { GraphQLError as BaseGraphQLError } from 'graphql';
|
||||
import { ApolloError as BaseApolloError } from 'apollo-client';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import { ApolloOperationContext } from '../types';
|
||||
import { ApolloErrorHandlerResultInterface } from './ApolloErrorHandlerResult';
|
||||
|
||||
export enum ApolloErrorType {
|
||||
NETWORK_ERROR = 'NETWORK_ERROR',
|
||||
SERVER_ERROR = 'SERVER_ERROR',
|
||||
UNAUTHORIZED_ERROR = 'UNAUTHORIZED_ERROR',
|
||||
BAD_USER_INPUT = 'BAD_USER_INPUT',
|
||||
INPUT_VALIDATION_ERROR = 'INPUT_VALIDATION_ERROR',
|
||||
}
|
||||
|
||||
// Upstream type declares networkError as Error, but it can contain additional properties, we override to add these
|
||||
export type ApolloError = BaseApolloError & {
|
||||
networkError: ApolloNetworkError | null;
|
||||
graphQLErrors: GraphQLError[];
|
||||
};
|
||||
|
||||
export interface ApolloNetworkError extends Error {
|
||||
statusCode?: number;
|
||||
response?: any;
|
||||
result?: {
|
||||
errors: GraphQLError[];
|
||||
};
|
||||
}
|
||||
|
||||
export type GraphQLError = Omit<BaseGraphQLError, 'message'> & {
|
||||
message: string | Record<string, any>;
|
||||
};
|
||||
export type ProcessedApolloError =
|
||||
| NetworkError
|
||||
| ServerError
|
||||
| UnauthorizedError
|
||||
| UserInputError
|
||||
| InputValidationError;
|
||||
|
||||
export interface NetworkError {
|
||||
type: ApolloErrorType.NETWORK_ERROR;
|
||||
error: Error;
|
||||
message: string;
|
||||
statusCode?: number;
|
||||
}
|
||||
|
||||
export interface ServerError {
|
||||
type: ApolloErrorType.SERVER_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface UnauthorizedError {
|
||||
type: ApolloErrorType.UNAUTHORIZED_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface UserInputError {
|
||||
type: ApolloErrorType.BAD_USER_INPUT;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface InputValidationError {
|
||||
type: ApolloErrorType.INPUT_VALIDATION_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
invalidArgs: string[];
|
||||
violations: ValidationRuleViolation[];
|
||||
}
|
||||
|
||||
export interface ValidationRuleViolation {
|
||||
path: string[];
|
||||
message: string;
|
||||
value?: any;
|
||||
}
|
||||
|
||||
export type ApolloOperationErrorHandlerFunction<
|
||||
TError = BaseApolloError,
|
||||
TApp extends Vue = Vue,
|
||||
TContext = ApolloOperationContext,
|
||||
TResult = ApolloErrorHandlerResultInterface,
|
||||
> = (error: TError, app: TApp, context?: TContext) => TResult;
|
||||
@@ -1,25 +0,0 @@
|
||||
import { ApolloErrorProcessor } from './ApolloErrorProcessor';
|
||||
import {
|
||||
ApolloError,
|
||||
ApolloErrorHandlerResult,
|
||||
ApolloOperationContext,
|
||||
ApolloOperationErrorHandlerFunction,
|
||||
} from './types';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
|
||||
/**
|
||||
* This is a simple example of an error handler function. You can copy this and implement your own in your application.
|
||||
*/
|
||||
export const handleApolloError: ApolloOperationErrorHandlerFunction<ApolloError, Vue> = (
|
||||
error: ApolloError,
|
||||
app: Vue,
|
||||
context?: ApolloOperationContext,
|
||||
): ApolloErrorHandlerResult => {
|
||||
const processor = new ApolloErrorProcessor(error, app, context ?? {});
|
||||
|
||||
processor.showErrorNotifications();
|
||||
|
||||
return {
|
||||
processedErrors: processor.processedErrors,
|
||||
};
|
||||
};
|
||||
+1
-2
@@ -2,10 +2,9 @@
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from './ApolloErrorProcessor';
|
||||
export * from './handleApolloError';
|
||||
export * from './mutation';
|
||||
export * from './query';
|
||||
export * from './subscription';
|
||||
export * from './types';
|
||||
export * from './decorator/index';
|
||||
export * from './error/index';
|
||||
|
||||
+19
-20
@@ -6,13 +6,13 @@ import { FetchPolicy, MutationBaseOptions } from 'apollo-client/core/watchQueryO
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import mapValues from 'lodash.mapvalues';
|
||||
import isPlainObject from 'lodash.isplainobject';
|
||||
import { ApolloOperationContext } from './types';
|
||||
import {
|
||||
ApolloErrorHandlerResult,
|
||||
ApolloOperationContext,
|
||||
ApolloErrorHandlerResultInterface,
|
||||
ApolloOperationErrorHandlerFunction,
|
||||
ProcessedApolloError,
|
||||
ValidationRuleViolation,
|
||||
} from './types';
|
||||
} from './error';
|
||||
|
||||
export type ApolloComponentMutationFunction<R = any, TVariables = OperationVariables> = (
|
||||
options: MutationBaseOptions<R, TVariables> &
|
||||
@@ -33,18 +33,17 @@ export type ApolloMutationClient<TResult, TVariables extends OperationVariables>
|
||||
// Mutation function with typings
|
||||
export type MutationOperationFunction<TResult, TVariables extends OperationVariables, TError = ApolloError> = (
|
||||
app: VueAppWithApollo,
|
||||
params: Omit<MutationOperationParams<TVariables, TError>, 'mutation'>,
|
||||
params: Omit<MutationOperationParams<TResult, TVariables, TError>, 'mutation'>,
|
||||
client?: ApolloMutationClient<TResult, TVariables>,
|
||||
) => Promise<MutationResult<TResult>>;
|
||||
|
||||
// Parameters given to a MutationOperationFunction
|
||||
export interface MutationOperationParams<
|
||||
TResult,
|
||||
TVariables extends OperationVariables,
|
||||
TError = ApolloError,
|
||||
TContext = ApolloOperationContext
|
||||
> {
|
||||
mutation: DocumentNode;
|
||||
variables: TVariables;
|
||||
TContext = ApolloOperationContext,
|
||||
> extends MutationOptions<TResult, TVariables> {
|
||||
context?: TContext;
|
||||
onError?: ApolloOperationErrorHandlerFunction<TError>;
|
||||
}
|
||||
@@ -83,13 +82,13 @@ export async function mutateWithErrorHandling<
|
||||
TResult,
|
||||
TVariables extends OperationVariables,
|
||||
TError,
|
||||
TApp extends VueAppWithApollo = VueAppWithApollo
|
||||
TApp extends VueAppWithApollo = VueAppWithApollo,
|
||||
>(
|
||||
app: TApp,
|
||||
{ mutation, variables, onError, context }: MutationOperationParams<TVariables, TError>,
|
||||
params: MutationOperationParams<TResult, TVariables, TError>,
|
||||
client?: ApolloMutationClient<TResult, TVariables>,
|
||||
): Promise<MutationResult<TResult>> {
|
||||
const mutate =
|
||||
const mutate: ApolloClientMutationFunction | ApolloComponentMutationFunction =
|
||||
client === undefined
|
||||
? app.$apollo.mutate.bind(app.$apollo)
|
||||
: typeof client === 'function'
|
||||
@@ -98,8 +97,8 @@ export async function mutateWithErrorHandling<
|
||||
|
||||
try {
|
||||
const result = await mutate({
|
||||
mutation,
|
||||
variables: cleanInput(variables),
|
||||
...params,
|
||||
variables: params.variables != null ? cleanInput(params.variables) : undefined,
|
||||
});
|
||||
|
||||
if (result == null) {
|
||||
@@ -108,12 +107,13 @@ export async function mutateWithErrorHandling<
|
||||
|
||||
return { success: true, data: result.data };
|
||||
} catch (error) {
|
||||
const errorHandlerResult: ApolloErrorHandlerResult | undefined =
|
||||
const { onError, context } = params;
|
||||
const errorHandlerResult: ApolloErrorHandlerResultInterface | undefined =
|
||||
onError != null ? onError(error, app, context) : undefined;
|
||||
|
||||
return {
|
||||
success: false,
|
||||
errors: errorHandlerResult?.processedErrors,
|
||||
errors: errorHandlerResult?.allErrors,
|
||||
validationRuleViolations: errorHandlerResult?.validationRuleViolations,
|
||||
};
|
||||
}
|
||||
@@ -123,23 +123,22 @@ export function createMutationFunction<
|
||||
TResult,
|
||||
TVariables extends OperationVariables,
|
||||
TError = ApolloError,
|
||||
TApp extends VueAppWithApollo = VueAppWithApollo
|
||||
TApp extends VueAppWithApollo = VueAppWithApollo,
|
||||
>(
|
||||
mutation: DocumentNode,
|
||||
onError?: ApolloOperationErrorHandlerFunction<TError, TApp>,
|
||||
): MutationOperationFunction<TResult, TVariables, TError> {
|
||||
return (
|
||||
app: TApp,
|
||||
params: Omit<MutationOperationParams<TVariables, TError>, 'mutation'>,
|
||||
params: Omit<MutationOperationParams<TResult, TVariables, TError>, 'mutation'>,
|
||||
client?: ApolloMutationClient<TResult, TVariables>,
|
||||
): Promise<MutationResult<TResult>> => {
|
||||
return mutateWithErrorHandling(
|
||||
app,
|
||||
{
|
||||
mutation,
|
||||
variables: params.variables,
|
||||
onError: params.onError ?? onError,
|
||||
context: params.context,
|
||||
onError,
|
||||
...params,
|
||||
},
|
||||
client,
|
||||
);
|
||||
|
||||
+12
-32
@@ -1,33 +1,9 @@
|
||||
import { ApolloError, OperationVariables } from 'apollo-client';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import { ErrorHandler, VueApolloQueryDefinition, VueApolloSubscribeToMoreOptions } from 'vue-apollo/types/options';
|
||||
import { ErrorHandler, VueApolloQueryDefinition } from 'vue-apollo/types/options';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import { ApolloOperationErrorHandlerFunction } from './types';
|
||||
|
||||
type OverrideThis<F, T> = F extends (...args: infer A) => infer B ? (this: T, ...args: A) => B : F;
|
||||
|
||||
type OverrideAllThis<O, T> = {
|
||||
[key in keyof O]: OverrideThis<O[key], T>;
|
||||
};
|
||||
|
||||
type SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables> = OverrideAllThis<
|
||||
Omit<VueApolloSubscribeToMoreOptions<TResult, TVariables>, 'updateQuery' | 'variables'>,
|
||||
TComponent
|
||||
> & {
|
||||
variables?: (this: TComponent) => any;
|
||||
updateQuery?: UpdateQueryFn<TComponent, TResult, any, any>; // TODO: How should we pass subscript data & variables types?
|
||||
};
|
||||
|
||||
type UpdateQueryFn<TComponent = any, TResult = any, TSubscriptionVariables = any, TSubscriptionData = any> = (
|
||||
this: TComponent,
|
||||
previousQueryResult: TResult,
|
||||
options: {
|
||||
subscriptionData: {
|
||||
data: TSubscriptionData;
|
||||
};
|
||||
variables?: TSubscriptionVariables;
|
||||
},
|
||||
) => TResult;
|
||||
import { ApolloOperationErrorHandlerFunction } from './error';
|
||||
import { OverrideAllThis, SubscribeToMoreOptionsPatched } from './types';
|
||||
|
||||
export interface VueApolloQueryDefinitionPatched<TComponent extends Vue = Vue, TResult = any, TVariables = any>
|
||||
extends OverrideAllThis<
|
||||
@@ -39,13 +15,17 @@ export interface VueApolloQueryDefinitionPatched<TComponent extends Vue = Vue, T
|
||||
| SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables>
|
||||
| Array<SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables>>;
|
||||
loadingKey?: keyof TComponent;
|
||||
|
||||
// added here pending upstream fix for missing types https://github.com/vuejs/vue-apollo/pull/1257
|
||||
throttle?: number;
|
||||
debounce?: number;
|
||||
}
|
||||
|
||||
export type VueApolloSmartQueryErrorHandler<
|
||||
TResult = any,
|
||||
TVariables = OperationVariables,
|
||||
TError = ApolloError,
|
||||
TComponent extends Vue = Vue
|
||||
TComponent extends Vue = Vue,
|
||||
> = (
|
||||
error: TError,
|
||||
vm: TComponent,
|
||||
@@ -58,13 +38,13 @@ export type VueApolloSmartQueryOptions<
|
||||
TResult = any,
|
||||
TVariables = OperationVariables,
|
||||
TError = ApolloError,
|
||||
TComponent extends Vue = Vue
|
||||
TComponent extends Vue = Vue,
|
||||
> = VueApolloQueryDefinitionPatched<TComponent, TResult, TVariables> & {
|
||||
error?: VueApolloSmartQueryErrorHandler<TResult, TVariables, TError, TComponent>;
|
||||
};
|
||||
|
||||
export type VueApolloSmartQueryOptionsFunction<TResult, TVariables, TError = ApolloError, TApp extends Vue = Vue> = <
|
||||
TComponent extends Vue = TApp
|
||||
TComponent extends Vue = TApp,
|
||||
>(
|
||||
options?: Partial<Omit<VueApolloSmartQueryOptions<TResult, TVariables, TError, TComponent>, 'query'>>,
|
||||
) => VueApolloSmartQueryOptions<TResult, TVariables, TError, TComponent>;
|
||||
@@ -93,8 +73,8 @@ export function createSmartQueryOptionsFunction<TResult, TVariables, TError = Ap
|
||||
...options,
|
||||
error:
|
||||
// we have to override vue-apollo types because they are incorrect
|
||||
((options.error as unknown) as ErrorHandler | undefined) ?? onError !== undefined
|
||||
? ((defaultErrorHandlerFn as unknown) as ErrorHandler)
|
||||
(options.error as unknown as ErrorHandler | undefined) ?? onError !== undefined
|
||||
? (defaultErrorHandlerFn as unknown as ErrorHandler)
|
||||
: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
+6
-6
@@ -2,13 +2,13 @@ import { ErrorHandler, VueApolloSubscriptionDefinition } from 'vue-apollo/types/
|
||||
import { ApolloError, OperationVariables } from 'apollo-client';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import { ApolloOperationErrorHandlerFunction } from './types';
|
||||
import { ApolloOperationErrorHandlerFunction } from './error';
|
||||
|
||||
export type VueApolloSmartSubscriptionErrorHandler<
|
||||
TResult = any,
|
||||
TVariables = OperationVariables,
|
||||
TError = ApolloError,
|
||||
TApp extends Vue = Vue
|
||||
TApp extends Vue = Vue,
|
||||
> = (
|
||||
error: TError,
|
||||
vm: TApp,
|
||||
@@ -21,7 +21,7 @@ export type VueApolloSmartSubscriptionOptions<
|
||||
TResult = any,
|
||||
TVariables = OperationVariables,
|
||||
TError = ApolloError,
|
||||
TApp extends Vue = Vue
|
||||
TApp extends Vue = Vue,
|
||||
> = Omit<VueApolloSubscriptionDefinition<TVariables>, 'error'> & {
|
||||
error?: VueApolloSmartSubscriptionErrorHandler<TResult, TVariables, TError, TApp>;
|
||||
};
|
||||
@@ -30,7 +30,7 @@ export function createSmartSubscriptionOptionsFunction<
|
||||
TResult,
|
||||
TVariables,
|
||||
TError = ApolloError,
|
||||
TApp extends Vue = Vue
|
||||
TApp extends Vue = Vue,
|
||||
>(
|
||||
query: DocumentNode,
|
||||
onError?: ApolloOperationErrorHandlerFunction<TError, TApp>,
|
||||
@@ -57,8 +57,8 @@ export function createSmartSubscriptionOptionsFunction<
|
||||
...options,
|
||||
error:
|
||||
// we have to override vue-apollo types because they are incorrect
|
||||
((options.error as unknown) as ErrorHandler | undefined) ?? onError !== undefined
|
||||
? ((defaultErrorHandlerFn as unknown) as ErrorHandler)
|
||||
(options.error as unknown as ErrorHandler | undefined) ?? onError !== undefined
|
||||
? (defaultErrorHandlerFn as unknown as ErrorHandler)
|
||||
: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
+26
-90
@@ -1,92 +1,28 @@
|
||||
import { ApolloError as BaseApolloError } from 'apollo-client';
|
||||
import { Vue } from 'vue/types/vue';
|
||||
import { GraphQLError as BaseGraphQLError } from 'graphql';
|
||||
import { VueApolloSubscribeToMoreOptions } from 'vue-apollo/types/options';
|
||||
|
||||
type OverrideThis<F, T> = F extends (...args: infer A) => infer B ? (this: T, ...args: A) => B : F;
|
||||
|
||||
export type OverrideAllThis<O, T> = {
|
||||
[key in keyof O]: OverrideThis<O[key], T>;
|
||||
};
|
||||
|
||||
export type SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables> = OverrideAllThis<
|
||||
Omit<VueApolloSubscribeToMoreOptions<TResult, TVariables>, 'updateQuery' | 'variables'>,
|
||||
TComponent
|
||||
> & {
|
||||
variables?: (this: TComponent) => any;
|
||||
updateQuery?: UpdateQueryFn<TComponent, TResult, any, any>; // TODO: How should we pass subscript data & variables types?
|
||||
};
|
||||
|
||||
type UpdateQueryFn<TComponent = any, TResult = any, TSubscriptionVariables = any, TSubscriptionData = any> = (
|
||||
this: TComponent,
|
||||
previousQueryResult: TResult,
|
||||
options: {
|
||||
subscriptionData: {
|
||||
data: TSubscriptionData;
|
||||
};
|
||||
variables?: TSubscriptionVariables;
|
||||
},
|
||||
) => TResult;
|
||||
|
||||
export type ApolloOperationContext<TAttrs = Record<string, any>> = TAttrs;
|
||||
|
||||
export enum ApolloErrorType {
|
||||
NETWORK_ERROR = 'NETWORK_ERROR',
|
||||
SERVER_ERROR = 'SERVER_ERROR',
|
||||
UNAUTHORIZED_ERROR = 'UNAUTHORIZED_ERROR',
|
||||
BAD_USER_INPUT = 'BAD_USER_INPUT',
|
||||
INPUT_VALIDATION_ERROR = 'INPUT_VALIDATION_ERROR',
|
||||
}
|
||||
|
||||
// Upstream type declares networkError as Error, but it can contain additional properties, we override to add these
|
||||
export type ApolloError = BaseApolloError & {
|
||||
networkError: ApolloNetworkError | null;
|
||||
graphQLErrors: GraphQLError[];
|
||||
};
|
||||
|
||||
export interface ApolloNetworkError extends Error {
|
||||
statusCode?: number;
|
||||
response?: any;
|
||||
result?: {
|
||||
errors: GraphQLError[];
|
||||
};
|
||||
}
|
||||
|
||||
export type GraphQLError = BaseGraphQLError & {
|
||||
message: string | Record<string, any>;
|
||||
};
|
||||
|
||||
export type ProcessedApolloError =
|
||||
| NetworkError
|
||||
| ServerError
|
||||
| UnauthorizedError
|
||||
| UserInputError
|
||||
| InputValidationError;
|
||||
|
||||
export interface NetworkError {
|
||||
type: ApolloErrorType.NETWORK_ERROR;
|
||||
error: Error;
|
||||
message: string;
|
||||
statusCode?: number;
|
||||
}
|
||||
|
||||
export interface ServerError {
|
||||
type: ApolloErrorType.SERVER_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface UnauthorizedError {
|
||||
type: ApolloErrorType.UNAUTHORIZED_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface UserInputError {
|
||||
type: ApolloErrorType.BAD_USER_INPUT;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface InputValidationError {
|
||||
type: ApolloErrorType.INPUT_VALIDATION_ERROR;
|
||||
error: Error;
|
||||
path?: readonly (string | number)[];
|
||||
message: string;
|
||||
invalidArgs: string[];
|
||||
violations: ValidationRuleViolation[];
|
||||
}
|
||||
|
||||
export interface ValidationRuleViolation {
|
||||
path: string[];
|
||||
message: string;
|
||||
value?: any;
|
||||
}
|
||||
|
||||
export interface ApolloErrorHandlerResult {
|
||||
processedErrors: ProcessedApolloError[];
|
||||
validationRuleViolations?: ValidationRuleViolation[];
|
||||
}
|
||||
|
||||
export type ApolloOperationErrorHandlerFunction<
|
||||
TError = BaseApolloError,
|
||||
TApp extends Vue = Vue,
|
||||
TContext = ApolloOperationContext
|
||||
> = (error: TError, app: TApp, context?: TContext) => ApolloErrorHandlerResult;
|
||||
|
||||
+4
-14
@@ -15,19 +15,9 @@
|
||||
"strictNullChecks": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
},
|
||||
"types": [
|
||||
"@types/node",
|
||||
"@types/jest",
|
||||
"vue-apollo/types"
|
||||
]
|
||||
"paths": {},
|
||||
"types": ["@types/node", "@types/jest", "vue-apollo/types"]
|
||||
},
|
||||
"include":[
|
||||
"src/**/*",
|
||||
"test/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"include": ["src/**/*", "test/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user