Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ad83a4fc6 | |||
| 5e99a3a354 | |||
| cbe2c251fb | |||
| ce94951550 | |||
| f1969bc88c | |||
| 7be078995e | |||
| f8b9bbd403 | |||
| 656eef7bcd | |||
| 6326ec8211 | |||
| 512eb9328b | |||
| 8f4c8cd88f | |||
| 0f312478bc | |||
| b022822a97 | |||
| ee396004a5 | |||
| 2077acddcb | |||
| e34cfec074 | |||
| 595733435b | |||
| e610d9dff0 | |||
| f5b28b0dc0 | |||
| c8f8c6c7b5 | |||
| 6ce30d8063 | |||
| c489613d12 | |||
| e835aac336 | |||
| a318b10e97 | |||
| 1ca08f363c | |||
| 0d68177297 | |||
| 47a9363624 | |||
| 02a95b0068 | |||
| 5f77e78dce | |||
| a55c4df8ac | |||
| ffe674e179 | |||
| 5316dffc79 | |||
| 2c102ffd86 | |||
| 653651af9e | |||
| 2579221ef3 | |||
| 1671a2a641 | |||
| 271af35ff3 | |||
| 38efa7f5fd | |||
| a184514f2c | |||
| 7a79a5c1fa | |||
| 4d55c37949 | |||
| 62e5db0159 | |||
| efe3394cc7 | |||
| 631f1c8836 | |||
| b0060fa347 | |||
| 51af6f30e4 | |||
| 0325a5bd2e | |||
| 46569adf84 | |||
| 1ada9125b7 | |||
| 0a260bd78e | |||
| f9415e58ba | |||
| 1abd6285a2 | |||
| 93d1f2b3fb | |||
| 3baa30e4b8 | |||
| b76d2b89f8 | |||
| 7593629c61 | |||
| 3fc3e664f4 | |||
| 2a24baba26 | |||
| 7008d8a401 | |||
| 75679dc539 | |||
| d6a4af0adf | |||
| 1e4bb13b14 | |||
| 345bb7e0b6 | |||
| fe75aaaf03 | |||
| 4f6b27c3cc | |||
| 60e04d13a2 | |||
| a5af67e962 | |||
| 70831ef914 | |||
| 3e20a074bf | |||
| 711ad93254 | |||
| 95a4720a24 | |||
| 2f26bfd45a | |||
| a00b05b352 | |||
| 5802d949e5 | |||
| 860db84f51 | |||
| 9ec02d15f0 | |||
| cb7ef32616 | |||
| 2e160a6f29 | |||
| 99f815dfbd | |||
| b10f95bd02 | |||
| a56f0168dd | |||
| 3426e2aff4 | |||
| 8571bc04ab | |||
| bb4b2b875e | |||
| f3382b7d76 | |||
| b0fc7d5506 | |||
| 33068e663b | |||
| 6ed1e9bdb1 | |||
| e6a80a4d88 | |||
| 2fe8c6b582 | |||
| 6bc078dbe4 | |||
| 7fd1b3977b | |||
| cce1dbd5a9 | |||
| 1c314402c5 | |||
| 2dae141096 | |||
| b58b07cf9b | |||
| 3b15071a3f | |||
| 770c2e3b98 | |||
| 6f33c7d785 | |||
| ced75f75ae | |||
| 3815b97099 | |||
| 5626dc129b | |||
| 7cacc37645 | |||
| 9f15bc22c5 | |||
| 16ca4b711b | |||
| e4a814126b | |||
| 4f6ddc91ba | |||
| 36ddad8c67 | |||
| 301e22b24e |
+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]
|
||||
|
||||
@@ -52,6 +52,8 @@ jobs:
|
||||
steps:
|
||||
# Setup
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
token: ${{ secrets.MADSCI_BUILD_USER_TOKEN }} # allows commit of any fixes to trigger a new workflow run
|
||||
- name: Use Node.js 12.x
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -64,9 +66,17 @@ jobs:
|
||||
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@v1
|
||||
with:
|
||||
prettier: true
|
||||
eslint: true
|
||||
eslint_args: "--ext '.ts,.js' --ignore-path '.gitignore' --ignore-pattern '.github/*'"
|
||||
continue_on_error: false
|
||||
auto_fix: true
|
||||
git_name: Madbot
|
||||
git_email: 64821814+madsci-bot@users.noreply.github.com
|
||||
|
||||
#
|
||||
# build job
|
||||
@@ -0,0 +1,13 @@
|
||||
# Ignore workflows
|
||||
.github
|
||||
|
||||
# Node modules
|
||||
node_modules
|
||||
|
||||
# Test results
|
||||
test/.results
|
||||
test/.coverage
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
@@ -1,3 +1,156 @@
|
||||
# vue-apollo-smart-ops
|
||||
|
||||
Create TypeScript-typed operation functions for your Vue Apollo queries and mutations.
|
||||
Creates TypeScript-typed operation functions for GraphQL queries and mutations compatible with
|
||||
[Vue Apollo](https://apollo.vuejs.org/).
|
||||
|
||||
This library is intended to be used together with the
|
||||
[`typescript-vue-apollo-smart-ops` plugin](https://www.graphql-code-generator.com/docs/plugins/typescript-vue-apollo-smart-ops)
|
||||
for [GraphQL Code Generator](https://www.graphql-code-generator.com/), but it may also be useful standalone.
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
npm install --save vue-apollo-smart-ops
|
||||
```
|
||||
|
||||
## Smart Query Usage
|
||||
|
||||
### `createSmartQueryOptionsFunction(query, onError?)`
|
||||
|
||||
Returns a generated function which returns a [Vue Apollo Smart Query options object](https://apollo.vuejs.org/api/smart-query.html#options)
|
||||
for the given query when called.
|
||||
|
||||
> ⚠️ Note: The returned function is not meant to execute the query itself. It is only used to configure a Vue Apollo
|
||||
> Smart Query. The responsibility for executing the query lies with Vue Apollo.
|
||||
|
||||
The returned function accepts an options object as its first argument, allowing variables and other parameters to be
|
||||
customised in runtime usage. Compared with creating an options object directly, the advantage here is that the options
|
||||
accepted by the generated function are fully type-checked based on the query definition - and 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 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`:
|
||||
|
||||
```typescript
|
||||
const useTodoListQuery = createSmartQueryOptionsFunction<TodosQuery, TodosQueryVariables>(gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`);
|
||||
```
|
||||
|
||||
This function can subsequently be called inside the `apollo` options of a Vue component to configure a Smart Query. The
|
||||
following example adds a `todos` Smart Query to a component, in Vue class component style:
|
||||
|
||||
```typescript
|
||||
@Component<TodoList>({
|
||||
apollo: {
|
||||
todos: useTodoListQuery<TodoList>({
|
||||
skip() {
|
||||
return this.foo === 'bar';
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
};
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
class TodoList extends Vue {
|
||||
todos: Todo[] | null = null;
|
||||
|
||||
get foo(): string {
|
||||
return 'bar';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `@SmartQuery(options)`
|
||||
|
||||
The `@SmartQuery()` decorator works with your generated options functions to enable the declaration of Smart Queries
|
||||
within the body of a Vue class component, instead of in the component options. This helps to keep the data property and
|
||||
its query options together in one place.
|
||||
|
||||
The following example is equivalent to the previous example but using the decorated syntax style:
|
||||
|
||||
```typescript
|
||||
@Component
|
||||
class TodoList extends Vue {
|
||||
@SmartQuery(
|
||||
useTodoListQuery<TodoList>({
|
||||
skip() {
|
||||
return this.foo === 'bar';
|
||||
},
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
}),
|
||||
)
|
||||
todos: Todo[] | null = null;
|
||||
|
||||
get foo(): string {
|
||||
return 'bar';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Mutations Usage
|
||||
|
||||
### `createMutationFunction(mutation, onError?)`
|
||||
|
||||
Returns a generated function which executes a mutation and returns the result when called.
|
||||
|
||||
The returned function requires a Vue app instance as its first argument (from which the `$apollo` client will be
|
||||
accessed), and accepts an options object as its second argument, allowing variables and other parameters to be
|
||||
customised in runtime usage. Compared with executing a mutation using the Vue Apollo client directly, the advantage here
|
||||
is that the options accepted by the generated function are fully type-checked based on the operation definition - and
|
||||
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 the mutation operations in your project.
|
||||
|
||||
The following example manually creates a mutation function and assigns it to the variable `todoCreateMutation`:
|
||||
|
||||
```typescript
|
||||
const todoCreateMutation = createMutationFunction<TodoCreateMutation, TodoCreateMutationVariables>(gql`
|
||||
mutation TodoCreate($input: TodoInput!) {
|
||||
todoCreate(input: $input) {
|
||||
todo {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
```
|
||||
|
||||
The following example demonstrates how to call this mutation from a method on a component:
|
||||
|
||||
```typescript
|
||||
@Component
|
||||
class TodoList extends Vue {
|
||||
async onClickCreateTodoButton(): Promise<void> {
|
||||
const result = await todoCreateMutation(this, {
|
||||
variables: {
|
||||
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,
|
||||
|
||||
+15
-22
@@ -1,24 +1,17 @@
|
||||
const { pathsToModuleNameMapper } = require('ts-jest/utils');
|
||||
const { compilerOptions } = require('./tsconfig');
|
||||
|
||||
module.exports = {
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/$1',
|
||||
'^~/(.*)$': '<rootDir>/$1',
|
||||
'^vue$': 'vue/dist/vue.common.js',
|
||||
},
|
||||
moduleFileExtensions: ['js', 'ts', 'vue', 'json'],
|
||||
transform: {
|
||||
'^.+\\.js$': 'babel-jest',
|
||||
'^.+\\.ts?$': 'ts-jest',
|
||||
'.*\\.(vue)$': 'vue-jest',
|
||||
},
|
||||
collectCoverage: false,
|
||||
collectCoverageFrom: ['<rootDir>/components/**/*.vue', '<rootDir>/pages/**/*.vue'],
|
||||
reporters: [
|
||||
'default',
|
||||
[
|
||||
'jest-html-reporters',
|
||||
{
|
||||
filename: 'test/.results/test-results.html',
|
||||
},
|
||||
],
|
||||
],
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/src/', '<rootDir>/test/'],
|
||||
testRegex: '\\.(spec|e2e-spec)\\.ts$',
|
||||
testPathIgnorePatterns: ['/node_modules/'],
|
||||
testTimeout: 20000,
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
|
||||
prefix: '<rootDir>/',
|
||||
}),
|
||||
coveragePathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/test/'],
|
||||
coverageDirectory: '<rootDir>/test/.coverage',
|
||||
reporters: ['default'],
|
||||
};
|
||||
|
||||
Generated
+2787
-3170
File diff suppressed because it is too large
Load Diff
+28
-24
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-apollo-smart-ops",
|
||||
"version": "0.0.2",
|
||||
"version": "0.1.0",
|
||||
"description": "Create TypeScript-typed operation functions for your Vue Apollo queries and mutations.",
|
||||
"author": "Madscience Ltd",
|
||||
"license": "MIT",
|
||||
@@ -15,11 +15,12 @@
|
||||
"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",
|
||||
"test:watch": "jest --watch",
|
||||
"test:ci": "rimraf test/.results && mkdirp test/.results && jest --ci --runInBand --passWithNoTests",
|
||||
"test:ci": "jest --ci --runInBand",
|
||||
"version": "npm run build",
|
||||
"postversion": "npm run postbuild",
|
||||
"release": "np --contents dist/",
|
||||
@@ -29,6 +30,9 @@
|
||||
"lodash.isplainobject": "^4.0",
|
||||
"lodash.mapvalues": "^4.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"vue-class-component": "^7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"apollo-client": ">=2.6",
|
||||
"apollo-link": ">=1.2",
|
||||
@@ -37,38 +41,38 @@
|
||||
"vue-apollo": ">=3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "26.0.22",
|
||||
"@types/jest": "27.0.1",
|
||||
"@types/lodash.isplainobject": "4.0.6",
|
||||
"@types/lodash.mapvalues": "4.6.6",
|
||||
"@typescript-eslint/eslint-plugin": "4.21.0",
|
||||
"@typescript-eslint/parser": "4.21.0",
|
||||
"@vue/test-utils": "1.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "4.30.0",
|
||||
"@typescript-eslint/parser": "4.30.0",
|
||||
"@vue/test-utils": "1.2.2",
|
||||
"apollo-client": "2.6.10",
|
||||
"apollo-link": "1.2.14",
|
||||
"barrelsby": "2.2.0",
|
||||
"dotenv-cli": "4.0.0",
|
||||
"eslint": "7.23.0",
|
||||
"eslint-config-prettier": "7.2.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jest": "24.3.4",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"eslint-plugin-jest": "24.4.0",
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"eslint-plugin-promise": "4.3.1",
|
||||
"eslint-plugin-vue": "7.8.0",
|
||||
"graphql": "15.5.0",
|
||||
"husky": "6.0.0",
|
||||
"jest": "26.6.3",
|
||||
"jest-html-reporters": "2.1.3",
|
||||
"lint-staged": "10.5.4",
|
||||
"eslint-plugin-promise": "5.1.0",
|
||||
"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",
|
||||
"mkdirp": "1.0.4",
|
||||
"np": "7.4.0",
|
||||
"prettier": "2.2.1",
|
||||
"np": "7.5.0",
|
||||
"prettier": "2.3.2",
|
||||
"rimraf": "3.0.2",
|
||||
"ts-jest": "26.5.4",
|
||||
"typescript": "4.2.3",
|
||||
"vue": "2.6.12",
|
||||
"ts-jest": "27.0.5",
|
||||
"typescript": "4.4.2",
|
||||
"vue": "2.6.14",
|
||||
"vue-apollo": "3.0.7",
|
||||
"vue-jest": "3.0.7"
|
||||
"vue-class-component": "7.2.6",
|
||||
"vue-property-decorator": "9.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.9.0"
|
||||
|
||||
+2
-6
@@ -12,12 +12,8 @@
|
||||
"prCreation": "not-pending",
|
||||
"stabilityDays": 3,
|
||||
"rebaseWhen": "conflicted",
|
||||
"labels": [
|
||||
"dependencies"
|
||||
],
|
||||
"reviewers": [
|
||||
"sgarner"
|
||||
],
|
||||
"labels": ["dependencies"],
|
||||
"reviewers": ["sgarner"],
|
||||
"packageRules": [
|
||||
{
|
||||
"packagePatterns": ["eslint"],
|
||||
|
||||
@@ -18,7 +18,7 @@ export function isGraphQLError(error: GraphQLError | any): error is GraphQLError
|
||||
return error.extensions !== undefined;
|
||||
}
|
||||
|
||||
export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = ApolloOperationContext> {
|
||||
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.',
|
||||
@@ -39,7 +39,13 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
this.processedErrors = this.processApolloError(error);
|
||||
}
|
||||
|
||||
public abstract showErrorNotifications(): void;
|
||||
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) {
|
||||
@@ -93,7 +99,30 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
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 AbstractApolloErrorProcessor).FriendlyMessages[errorCode] ?? errorMessage;
|
||||
return (this.constructor as typeof ApolloErrorProcessor).FriendlyMessages[errorCode] ?? errorMessage;
|
||||
}
|
||||
|
||||
protected processErrorMessage(message: GraphQLError['message']): string {
|
||||
if (typeof message === 'object') {
|
||||
if (message.error != null) {
|
||||
return message.error;
|
||||
}
|
||||
|
||||
return 'Unknown error: ' + JSON.stringify(message);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
protected normalizeError(error: GraphQLError | Error): Error {
|
||||
if (isGraphQLError(error)) {
|
||||
return {
|
||||
...error,
|
||||
message: this.processErrorMessage(error.message),
|
||||
};
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
private processApolloError(error: ApolloError): ProcessedApolloError[] {
|
||||
@@ -134,8 +163,8 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
// Unauthorized (not logged in, or not allowed) error
|
||||
const processedError: UnauthorizedError = {
|
||||
type: ApolloErrorType.UNAUTHORIZED_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
error: this.normalizeError(error),
|
||||
message: this.processErrorMessage(error.message),
|
||||
path: error.path,
|
||||
};
|
||||
|
||||
@@ -148,8 +177,8 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
// User input validation error
|
||||
const processedError: InputValidationError = {
|
||||
type: ApolloErrorType.INPUT_VALIDATION_ERROR,
|
||||
error,
|
||||
message: error.message,
|
||||
error: this.normalizeError(error),
|
||||
message: this.processErrorMessage(error.message),
|
||||
path: error.path,
|
||||
invalidArgs: error.extensions.invalidArgs,
|
||||
violations: error.extensions.validationErrors,
|
||||
@@ -163,9 +192,9 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
// Other GraphQL resolver error - probably a bug
|
||||
const processedError: ServerError = {
|
||||
type: error.extensions?.code != null ? error.extensions.code : ApolloErrorType.SERVER_ERROR,
|
||||
error,
|
||||
error: this.normalizeError(error),
|
||||
message: this.getFriendlyMessage('INTERNAL_SERVER_ERROR', this.processErrorMessage(error.message)),
|
||||
path: error.path,
|
||||
message: this.getFriendlyMessage('INTERNAL_SERVER_ERROR', error.message),
|
||||
};
|
||||
|
||||
this.onServerError(processedError);
|
||||
@@ -198,16 +227,4 @@ export abstract class AbstractApolloErrorProcessor<TApp = Vue, TContext = Apollo
|
||||
|
||||
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,285 @@
|
||||
import { ApolloQueryResult } from 'apollo-client';
|
||||
import gql from 'graphql-tag';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { createSmartQueryOptionsFunction } from '../query';
|
||||
import { SmartQuery } from './SmartQuery';
|
||||
|
||||
interface Todo {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface QueryResult {
|
||||
todos: Todo[];
|
||||
__typename?: 'Query';
|
||||
}
|
||||
|
||||
interface QueryVariables {
|
||||
skip?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
describe('@SmartQuery() decorator', () => {
|
||||
it('Adds basic query options', () => {
|
||||
@Component
|
||||
class TodoList extends Vue {
|
||||
@SmartQuery({
|
||||
query: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
})
|
||||
todos!: Todo[];
|
||||
|
||||
get vars(): QueryVariables {
|
||||
return {
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TodoList();
|
||||
|
||||
expect(instance.$options.apollo?.todos).toEqual(
|
||||
expect.objectContaining({
|
||||
query: expect.objectContaining({ definitions: expect.arrayContaining([]) }),
|
||||
variables: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('Works with a query options function', () => {
|
||||
const useTodoListQuery = createSmartQueryOptionsFunction<QueryResult, QueryVariables>(gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
@Component<TodoList>({})
|
||||
class TodoList extends Vue {
|
||||
@SmartQuery(
|
||||
useTodoListQuery<TodoList>({
|
||||
skip() {
|
||||
return this.foo === 'bar';
|
||||
},
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
loadingKey: 'loading',
|
||||
}),
|
||||
)
|
||||
todos!: Todo[];
|
||||
|
||||
loading: number = 0;
|
||||
|
||||
get vars(): QueryVariables {
|
||||
return {
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
};
|
||||
}
|
||||
|
||||
get foo(): string {
|
||||
return 'bar';
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TodoList();
|
||||
|
||||
expect(instance.$options.apollo?.todos).toEqual(
|
||||
expect.objectContaining({
|
||||
query: expect.objectContaining({ definitions: expect.arrayContaining([]) }),
|
||||
skip: expect.any(Function),
|
||||
variables: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('Works with class inheritance and update, result methods', () => {
|
||||
@Component
|
||||
class TodoList extends Vue {
|
||||
@SmartQuery({
|
||||
query: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
})
|
||||
todos!: Todo[];
|
||||
|
||||
get vars(): QueryVariables {
|
||||
return {
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class TodoList2 extends TodoList {
|
||||
@SmartQuery<TodoList2, QueryResult>({
|
||||
query: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
update(data: QueryResult) {
|
||||
// data: QueryResult
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
result({ data, errors, loading }) {
|
||||
this.doThings();
|
||||
},
|
||||
subscribeToMore: {
|
||||
document: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
},
|
||||
})
|
||||
todos!: Todo[];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
doThings() {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new TodoList2();
|
||||
|
||||
expect(instance.$options.apollo?.todos).toEqual(
|
||||
expect.objectContaining({
|
||||
query: expect.objectContaining({ definitions: expect.arrayContaining([]) }),
|
||||
variables: expect.any(Function),
|
||||
update: expect.any(Function),
|
||||
result: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('Supports subscribeToMore with updateQuery method', () => {
|
||||
@Component
|
||||
class TodoList extends Vue {
|
||||
@SmartQuery({
|
||||
query: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
})
|
||||
todos!: Todo[];
|
||||
|
||||
get vars(): QueryVariables {
|
||||
return {
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class TodoList3 extends TodoList {
|
||||
@SmartQuery<TodoList3, QueryResult, QueryVariables>({
|
||||
query: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
update(data: QueryResult) {
|
||||
// data: QueryResult
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
||||
result(data: ApolloQueryResult<QueryResult>) {},
|
||||
subscribeToMore: [
|
||||
{
|
||||
document: gql`
|
||||
query Todos($skip: Int, $limit: Int) {
|
||||
todos(skip: $skip, limit: $limit) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return this.vars;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
updateQuery(prev, { subscriptionData: { data }, variables }) {
|
||||
return {
|
||||
...prev,
|
||||
todos: [
|
||||
{ id: '1', title: 'Int' },
|
||||
{ id: '2', title: 'Float' },
|
||||
{ id: '3', title: 'String' },
|
||||
],
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
todos!: Todo[];
|
||||
}
|
||||
|
||||
const instance = new TodoList3();
|
||||
|
||||
expect(instance.$options.apollo?.todos).toEqual(
|
||||
expect.objectContaining({
|
||||
query: expect.objectContaining({ definitions: expect.arrayContaining([]) }),
|
||||
variables: expect.any(Function),
|
||||
update: expect.any(Function),
|
||||
result: expect.any(Function),
|
||||
subscribeToMore: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
document: expect.objectContaining({ definitions: expect.arrayContaining([]) }),
|
||||
variables: expect.any(Function),
|
||||
updateQuery: expect.any(Function),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Based on https://github.com/chanlito/vue-apollo-decorator by chanlito ❤️
|
||||
*/
|
||||
|
||||
import { ApolloError, OperationVariables } from 'apollo-client';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import Vue from 'vue';
|
||||
import { createDecorator, VueDecorator } from 'vue-class-component';
|
||||
import { VueApolloSmartQueryOptions } from '../query';
|
||||
|
||||
export function SmartQuery<TApp = any, TResult = any, TVariables = OperationVariables, TError = ApolloError>(
|
||||
options: TApp extends Vue ? VueApolloSmartQueryOptions<TResult, TVariables, TError, TApp> : DocumentNode,
|
||||
): VueDecorator {
|
||||
return createDecorator((componentOptions: any, k: string) => {
|
||||
componentOptions.apollo = componentOptions.apollo || {};
|
||||
componentOptions.apollo[k] = options;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from './SmartQuery';
|
||||
@@ -0,0 +1,25 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
+3
-1
@@ -2,8 +2,10 @@
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from './AbstractApolloErrorProcessor';
|
||||
export * from './ApolloErrorProcessor';
|
||||
export * from './handleApolloError';
|
||||
export * from './mutation';
|
||||
export * from './query';
|
||||
export * from './subscription';
|
||||
export * from './types';
|
||||
export * from './decorator/index';
|
||||
|
||||
+19
-16
@@ -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,19 +82,23 @@ 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 =
|
||||
client === undefined ? app.$apollo : typeof client === 'function' ? client : client.mutate.bind(client);
|
||||
const mutate: ApolloClientMutationFunction | ApolloComponentMutationFunction =
|
||||
client === undefined
|
||||
? app.$apollo.mutate.bind(app.$apollo)
|
||||
: typeof client === 'function'
|
||||
? client
|
||||
: client.mutate.bind(client);
|
||||
|
||||
try {
|
||||
const result = await mutate({
|
||||
mutation,
|
||||
variables: cleanInput(variables),
|
||||
...params,
|
||||
variables: params.variables != null ? cleanInput(params.variables) : undefined,
|
||||
});
|
||||
|
||||
if (result == null) {
|
||||
@@ -104,6 +107,7 @@ export async function mutateWithErrorHandling<
|
||||
|
||||
return { success: true, data: result.data };
|
||||
} catch (error) {
|
||||
const { onError, context } = params;
|
||||
const errorHandlerResult: ApolloErrorHandlerResult | undefined =
|
||||
onError != null ? onError(error, app, context) : undefined;
|
||||
|
||||
@@ -119,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,
|
||||
);
|
||||
|
||||
+57
-14
@@ -1,39 +1,82 @@
|
||||
import { VueApolloQueryDefinition, ErrorHandler } from 'vue-apollo/types/options';
|
||||
import { ApolloError, OperationVariables } from 'apollo-client';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import { ErrorHandler, VueApolloQueryDefinition, VueApolloSubscribeToMoreOptions } 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;
|
||||
|
||||
export interface VueApolloQueryDefinitionPatched<TComponent extends Vue = Vue, TResult = any, TVariables = any>
|
||||
extends OverrideAllThis<
|
||||
Omit<VueApolloQueryDefinition<TResult, TVariables>, 'subscribeToMore' | 'variables' | 'loadingKey'>,
|
||||
TComponent
|
||||
> {
|
||||
variables?: ((this: TComponent) => TVariables) | TVariables;
|
||||
subscribeToMore?:
|
||||
| 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,
|
||||
TApp extends Vue = Vue
|
||||
TComponent extends Vue = Vue,
|
||||
> = (
|
||||
error: TError,
|
||||
vm: TApp,
|
||||
vm: TComponent,
|
||||
key: string,
|
||||
type: 'query',
|
||||
options: VueApolloSmartQueryOptions<TResult, TVariables, TError, TApp>,
|
||||
options: VueApolloSmartQueryOptions<TResult, TVariables, TError, TComponent>,
|
||||
) => void;
|
||||
|
||||
// Type of VueApolloQueryDefinition['subscribeToMore'] is incompatible with generated QueryVariables types.
|
||||
// Omitting it here since we don't use it anyway.
|
||||
export type VueApolloSmartQueryOptions<
|
||||
TResult = any,
|
||||
TVariables = OperationVariables,
|
||||
TError = ApolloError,
|
||||
TApp extends Vue = Vue
|
||||
> = Omit<VueApolloQueryDefinition<TResult, TVariables>, 'subscribeToMore' | 'error'> & {
|
||||
error?: VueApolloSmartQueryErrorHandler<TResult, TVariables, TError, TApp>;
|
||||
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,
|
||||
>(
|
||||
options?: Partial<Omit<VueApolloSmartQueryOptions<TResult, TVariables, TError, TComponent>, 'query'>>,
|
||||
) => VueApolloSmartQueryOptions<TResult, TVariables, TError, TComponent>;
|
||||
|
||||
export function createSmartQueryOptionsFunction<TResult, TVariables, TError = ApolloError, TApp extends Vue = Vue>(
|
||||
query: DocumentNode,
|
||||
onError?: ApolloOperationErrorHandlerFunction<TError, TApp>,
|
||||
): (
|
||||
options?: Partial<VueApolloSmartQueryOptions<TResult, TVariables, TError, TApp>>,
|
||||
) => VueApolloQueryDefinition<TResult, TVariables> {
|
||||
): VueApolloSmartQueryOptionsFunction<TResult, TVariables> {
|
||||
return (options = {}) => {
|
||||
const defaultErrorHandlerFn: VueApolloSmartQueryErrorHandler<TResult, TVariables, TError, TApp> = (
|
||||
error: TError,
|
||||
@@ -54,8 +97,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,
|
||||
};
|
||||
};
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@ 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,
|
||||
};
|
||||
};
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ export interface ApolloNetworkError extends Error {
|
||||
};
|
||||
}
|
||||
|
||||
export type GraphQLError = BaseGraphQLError & {
|
||||
export type GraphQLError = Omit<BaseGraphQLError, 'message'> & {
|
||||
message: string | Record<string, any>;
|
||||
};
|
||||
|
||||
@@ -88,5 +88,5 @@ export interface ApolloErrorHandlerResult {
|
||||
export type ApolloOperationErrorHandlerFunction<
|
||||
TError = BaseApolloError,
|
||||
TApp extends Vue = Vue,
|
||||
TContext = ApolloOperationContext
|
||||
TContext = ApolloOperationContext,
|
||||
> = (error: TError, app: TApp, context?: TContext) => ApolloErrorHandlerResult;
|
||||
|
||||
+4
-13
@@ -15,18 +15,9 @@
|
||||
"strictNullChecks": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
},
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./@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