227 Commits

Author SHA1 Message Date
renovate[bot] c38617df77 Lock file maintenance
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2022-07-11 01:41:06 +00:00
renovate[bot] 61c387113f Lock file maintenance 2022-07-11 01:39:16 +00:00
renovate[bot] 7b6e7c3018 Update Node.js to v16.16.0 2022-07-10 14:01:55 +00:00
renovate[bot] 015b51a598 Update eslint 2022-07-09 00:42:26 +00:00
renovate[bot] f4417a2a58 Update dependency dotenv-cli to v6 2022-07-07 12:42:53 +00:00
Simon Garner 0faf1ac6ba Merge pull request #158 from equalogic/revert-140-renovate/major-vue-monorepo
Revert "Update dependency vue to v3"
2022-07-02 08:27:27 +12:00
Simon Garner 2f53b7f101 Revert "Update dependency vue to v3"
This reverts commit d8182a9580.
2022-07-02 08:15:59 +12:00
renovate[bot] 753d4c8a6e Lock file maintenance 2022-06-27 02:27:41 +00:00
renovate[bot] d8182a9580 Update dependency vue to v3 2022-06-21 02:14:15 +00:00
renovate[bot] 2630d0b401 Update dependency typescript to v4.7.4 2022-06-20 20:43:54 +00:00
Renovate Bot 151d51f6e8 Lock file maintenance 2022-06-20 02:50:57 +00:00
renovate[bot] b970d3c454 Update dependency prettier to v2.7.1 2022-06-19 06:04:01 +00:00
Renovate Bot 19512cb6b2 Update eslint 2022-06-16 17:13:56 +00:00
Renovate Bot a228eaa04d Update eslint 2022-06-09 18:32:40 +00:00
Renovate Bot a592182e1c Update dependency eslint-plugin-jest to v26.5.3 2022-06-09 04:21:38 +00:00
Renovate Bot 7970865f2a Update dependency typescript to v4.7.3 2022-06-06 20:13:51 +00:00
Renovate Bot dc92f7c24b Lock file maintenance 2022-06-06 00:59:47 +00:00
Renovate Bot 384235bed9 Lock file maintenance 2022-06-06 00:58:35 +00:00
Renovate Bot 4987a48fec Update jest 2022-06-04 22:18:29 +00:00
Renovate Bot 619b76efcf Update Node.js to v16.15.1 2022-06-04 19:22:01 +00:00
Renovate Bot da427d5542 Lock file maintenance 2022-05-30 01:40:20 +00:00
Renovate Bot c9d101b99a Lock file maintenance 2022-05-30 01:38:51 +00:00
Renovate Bot 21cfccbfac Update dependency typescript to v4.7.2 2022-05-27 21:00:23 +00:00
Renovate Bot f91748e8d7 Update eslint 2022-05-26 18:10:01 +00:00
Renovate Bot 7e2f480a6c Lock file maintenance 2022-05-23 02:19:06 +00:00
Renovate Bot 71c5140462 Update dependency eslint-plugin-vue to v9 2022-05-21 18:19:03 +00:00
Renovate Bot aa8be3e99d Update dependency ts-jest to v27.1.5 2022-05-21 16:05:30 +00:00
Renovate Bot 2940dcff42 Update eslint to v5.25.0 2022-05-20 15:14:01 +00:00
Renovate Bot accd28fc19 Update jest 2022-05-17 22:11:06 +00:00
Renovate Bot 660baabe33 Update eslint 2022-05-12 18:31:51 +00:00
Renovate Bot 315c31389d Lock file maintenance 2022-05-09 00:42:34 +00:00
Renovate Bot 34336f9ece Lock file maintenance 2022-05-09 00:41:36 +00:00
Renovate Bot 4e30667a14 Update dependency @types/jest to v27.5.0 2022-05-05 22:43:18 +00:00
Renovate Bot 8e01a115ba Update eslint to v5.22.0 2022-05-05 17:23:39 +00:00
Renovate Bot c3138c7001 Lock file maintenance 2022-05-02 01:42:15 +00:00
Renovate Bot 6f8e30598c Update dependency typescript to v4.6.4 2022-05-01 22:52:33 +00:00
Renovate Bot 024c546345 Update Node.js to v16.15.0 2022-04-30 01:34:13 +00:00
Renovate Bot ce6fcb3fe6 Update eslint 2022-04-28 19:13:27 +00:00
Renovate Bot a37735daa5 Update dependency eslint-plugin-jest to v26.1.5 2022-04-25 23:46:21 +00:00
Renovate Bot f0591c0aa2 Update wearerequired/lint-action action to v2 2022-04-25 16:32:45 +00:00
Renovate Bot 06d70f250e Lock file maintenance 2022-04-25 04:20:35 +00:00
Renovate Bot bf915d7215 Update dependency @types/lodash.mapvalues to v4.6.7 2022-04-22 02:19:16 +00:00
Renovate Bot 92bc6a5932 Update dependency @types/lodash.isplainobject to v4.0.7 2022-04-21 23:31:07 +00:00
Renovate Bot d304a20ba2 Update eslint to v5.20.0 2022-04-21 17:36:29 +00:00
Renovate Bot 0734e360f6 Update dependency barrelsby to v2.3.4 2022-04-15 04:06:28 +00:00
Renovate Bot 70e79bfbf5 Update eslint 2022-04-14 17:47:06 +00:00
Renovate Bot 2c51549ef7 Update dependency eslint-plugin-jest to v26.1.4 2022-04-11 13:23:25 +00:00
Renovate Bot a6933cdb66 Lock file maintenance 2022-04-11 00:54:38 +00:00
Renovate Bot 927726fae6 Update dependency prettier to v2.6.2 2022-04-05 16:32:21 +00:00
Renovate Bot 62f86064dc Lock file maintenance 2022-04-04 00:22:29 +00:00
Renovate Bot 0610835df7 Update eslint 2022-03-31 17:04:51 +00:00
Renovate Bot 883a9da071 Update dependency dotenv-cli to v5.1.0 2022-03-28 21:19:36 +00:00
Renovate Bot e541af8201 Update dependency prettier to v2.6.1 2022-03-28 09:40:59 +00:00
Renovate Bot 1fa908d859 Lock file maintenance 2022-03-28 02:42:32 +00:00
Renovate Bot 39aa1b430e Update dependency typescript to v4.6.3 2022-03-27 23:54:23 +00:00
Renovate Bot 29cb45392f Update jest 2022-03-27 21:43:37 +00:00
Renovate Bot 441c897442 Update eslint to v5.16.0 2022-03-24 18:06:50 +00:00
Renovate Bot 5baa304add Update dependency eslint-plugin-jest to v26.1.2 2022-03-23 01:26:48 +00:00
Renovate Bot c160171ec9 Update dependency np to v7.6.1 2022-03-22 18:32:17 +00:00
Renovate Bot e229c69421 Update actions/cache action to v3 2022-03-21 11:20:46 +00:00
Renovate Bot 8ab911f4dd Update Node.js to v16.14.2 2022-03-21 05:58:03 +00:00
Renovate Bot b767ff94ff Lock file maintenance 2022-03-21 00:33:38 +00:00
Renovate Bot 05d4e1f117 Lock file maintenance 2022-03-21 00:32:34 +00:00
Renovate Bot 492a9fc70b Update dependency prettier to v2.6.0 2022-03-19 05:01:30 +00:00
Renovate Bot 4faf126fa3 Update eslint 2022-03-18 12:30:09 +00:00
Renovate Bot ce0a7c3d6d Update eslint to v5.14.0 2022-03-11 16:12:18 +00:00
Renovate Bot db56bc097d Lock file maintenance 2022-03-07 01:27:49 +00:00
Renovate Bot d61bb4da4f Update eslint 2022-03-05 20:59:33 +00:00
Renovate Bot 1b7eec07be Update dependency typescript to v4.6.2 2022-03-04 00:19:18 +00:00
Renovate Bot ea3798f1ec Update actions/upload-artifact action to v3 2022-03-03 18:45:00 +00:00
Renovate Bot a78c36250b Update actions/download-artifact action to v3 2022-03-02 18:57:14 +00:00
Renovate Bot bfcfd90bf5 Update dependency barrelsby to v2.3.3 2022-03-02 05:21:00 +00:00
Renovate Bot b6e3fd9a55 Update actions/checkout action to v3 2022-03-01 19:35:26 +00:00
Renovate Bot e67951c0c1 Lock file maintenance 2022-02-28 02:23:20 +00:00
Renovate Bot e9280799c9 Update dependency @types/jest to v27.4.1 2022-02-26 10:18:34 +00:00
Renovate Bot 3f036a1faa Update actions/setup-node action to v3 2022-02-25 11:23:11 +00:00
Renovate Bot 841eb0ef30 Update eslint 2022-02-25 09:28:39 +00:00
Renovate Bot 4305ee261c Lock file maintenance 2022-02-21 00:42:43 +00:00
Renovate Bot de5ed10fcf Update dependency eslint-plugin-jest to v26.1.1 2022-02-18 14:51:25 +00:00
Renovate Bot 0d327b14ec Update eslint 2022-02-17 19:51:14 +00:00
Renovate Bot 985c4d5b3f Lock file maintenance 2022-02-14 01:21:44 +00:00
Renovate Bot bbed27395a Update Node.js to v16.14.0 2022-02-11 20:27:38 +00:00
Renovate Bot e3ca73d34f Update jest 2022-02-11 11:00:51 +00:00
Renovate Bot fb20387229 Update eslint to v5.11.0 2022-02-10 18:42:37 +00:00
Renovate Bot 068b3cc87e Update dependency dotenv-cli to v5 2022-02-09 22:21:22 +00:00
Renovate Bot 364081a24c Lock file maintenance 2022-02-07 01:34:23 +00:00
Renovate Bot b629c232b2 Update eslint 2022-02-07 11:04:40 +13:00
Renovate Bot 1d2afb8f03 Update dependency eslint-plugin-promise to v6 2022-02-06 21:50:57 +00:00
Renovate Bot 9776978f50 Update dependency eslint-plugin-jest to v26 2022-02-06 21:49:53 +00:00
Renovate Bot 08c0686f05 Update dependency graphql to v15.8.0 2022-02-06 21:48:47 +00:00
Renovate Bot a45711f58b Update dependency typescript to v4.5.5 2022-02-06 21:48:00 +00:00
Renovate Bot 419d3880d2 Update dependency barrelsby to v2.3.2 2022-02-06 21:47:12 +00:00
Renovate Bot ad85560e70 Update jest 2022-02-07 10:43:26 +13:00
Simon Garner 8e4f74dc0d build: stop persisting nonexistent test-results artifact 2022-02-07 08:45:19 +13:00
Simon Garner 48b88f2989 deps: remove husky, lint-staged 2022-02-07 08:43:25 +13:00
Simon Garner 2c6f91d225 Sync package-lock 2022-02-07 08:42:40 +13:00
Simon Garner 26ba4f1678 Revert "Update dependency graphql to v16"
This reverts commit eb3f046325.
2022-02-07 08:41:55 +13:00
Simon Garner de80521bfa renovate: enable lockFileMaintenance 2022-02-07 08:41:20 +13:00
Simon Garner 29414d8e33 renovate: use automergeBranch mode 2022-02-07 08:41:20 +13:00
Simon Garner 1d9238c5d6 build: allow publish from workflow_dispatch event 2022-02-07 08:41:20 +13:00
Simon Garner 1ae2c62237 build: fix publish command, token secret 2022-02-07 08:41:20 +13:00
Simon Garner f17372e08d Use Node.js 16.x 2022-02-07 08:41:20 +13:00
Simon Garner 50d5f68848 build: update auto-lint bot token, identity 2022-02-07 08:41:20 +13:00
Simon Garner 67400160a4 build: set artifact retention-days, stop cleanup 2022-02-07 08:41:19 +13:00
Simon Garner d7e0132e23 build: remove unnecessary NPM token 2022-02-07 08:41:19 +13:00
Simon Garner e9e6625df5 Update repository URL 2022-02-07 08:31:03 +13:00
Renovate Bot ecf949e05a Update Node.js to v16.13.2 2022-01-14 01:13:25 +00:00
Renovate Bot eb3f046325 Update dependency graphql to v16 2021-12-07 23:11:09 +00:00
Renovate Bot d40772caf7 Update dependency prettier to v2.5.1 2021-12-07 19:16:38 +00:00
Renovate Bot a06db8d24b Update dependency jest to v27.4.3 2021-12-04 21:02:41 +00:00
Renovate Bot 67f82cfb51 Update Node.js to v16.13.1 2021-12-04 21:01:59 +00:00
Renovate Bot 01b93675d8 Update dependency dotenv-cli to v4.1.1 2021-12-02 13:41:10 +00:00
Renovate Bot 93262362a3 Update dependency prettier to v2.5.0 2021-11-29 18:02:16 +00:00
Renovate Bot 50d550a350 Update dependency eslint-plugin-jest to v25.3.0 2021-11-26 10:06:48 +00:00
Renovate Bot d880a87225 Update dependency lint-staged to v12.1.2 2021-11-25 11:01:21 +00:00
Renovate Bot c9e5f39b7a Update eslint 2021-11-24 11:43:46 +00:00
Renovate Bot 16565770ea Update dependency np to v7.6.0 2021-11-22 17:52:16 +00:00
Renovate Bot 9e927b6aac Update dependency @types/jest to v27.0.3 2021-11-22 03:56:14 +00:00
Renovate Bot be65185b76 Update dependency vue-apollo to v3.1.0 2021-11-21 20:33:48 +00:00
Renovate Bot 956bd7878c Update dependency typescript to v4.5.2 2021-11-20 22:20:39 +00:00
Renovate Bot 42d0681ff3 Update dependency @vue/test-utils to v1.3.0 2021-11-20 11:00:20 +00:00
Renovate Bot a7f8fbae9a Update dependency lint-staged to v12 2021-11-17 14:26:39 +00:00
Renovate Bot f64c30f3f3 Update eslint 2021-11-13 12:30:18 +00:00
Renovate Bot 8cd72c6359 Update dependency eslint-plugin-jest to v25.2.4 2021-11-11 12:05:51 +00:00
Renovate Bot b1cda614c3 Update dependency graphql-tag to v2.12.6 2021-11-09 19:04:06 +00:00
Renovate Bot 94730ccee8 Update dependency eslint-plugin-jest to v25.2.3 2021-11-08 00:45:06 +00:00
Renovate Bot a8107594a8 Update eslint to v5.3.0 2021-11-05 01:23:07 +00:00
Renovate Bot 385679b4a4 Update dependency dotenv-cli to v4.1.0 2021-11-02 19:10:42 +00:00
Renovate Bot 563f1ce2eb Update dependency eslint-plugin-vue to v8 2021-11-02 12:00:41 +00:00
Renovate Bot 8f3500295f Update dependency graphql to v15.7.2 2021-10-31 19:37:24 +00:00
Renovate Bot 8be0b8e07f Update dependency lint-staged to v11.2.6 2021-10-30 00:00:36 +00:00
Renovate Bot 2f6f9b4f13 Update Node.js to v16.13.0 2021-10-30 00:00:17 +00:00
Renovate Bot 81c8820b80 Update eslint 2021-10-28 22:27:15 +00:00
Simon Garner 94ba867b00 0.2.0-beta.1
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2021-10-28 16:41:08 +13:00
Simon Garner ae4ccedcc2 Merge pull request #101 from madscience/error-results
Make error handling easier to configure
2021-10-28 16:39:51 +13:00
Simon Garner 05ec76bf91 Make result type generic on ApolloOperationErrorHandlerFunction 2021-10-28 16:30:48 +13:00
Simon Garner 6923ead0e6 Replace ApolloErrorProcessor class with processApolloError function
Allows error handling to be configured through an options object instead of by re-implementing the class.
2021-10-28 16:22:56 +13:00
Simon Garner 9b0d0e06e4 Add ApolloErrorProcessor.result getter 2021-10-28 15:23:11 +13:00
Simon Garner e7396ee638 Add ApolloErrorHandlerResult class, refactor types 2021-10-28 15:15:49 +13:00
Simon Garner 766bd54a10 Move error handling code to error/ directory 2021-10-28 15:04:39 +13:00
Renovate Bot e4950fdfec Update Node.js to v16 2021-10-26 04:42:32 +00:00
Renovate Bot 6c154c0773 Update dependency husky to v7.0.4 2021-10-24 08:41:23 +00:00
Renovate Bot bd1a290007 Update jest 2021-10-22 11:28:55 +00:00
Renovate Bot 734182fedf Update eslint 2021-10-21 17:12:45 +00:00
Renovate Bot 54f9852313 Update dependency eslint-plugin-jest to v25 2021-10-20 15:09:07 +00:00
Renovate Bot 8f3626ce47 Update dependency eslint-plugin-import to v2.25.2 2021-10-16 01:52:34 +00:00
Renovate Bot 2805cad639 Update dependency typescript to v4.4.4 2021-10-15 23:29:32 +00:00
Renovate Bot 254afbda73 Update Node.js to v14.18.1 2021-10-15 20:05:10 +00:00
Renovate Bot cddb5a39c5 Update dependency lint-staged to v11.2.3 2021-10-13 22:49:28 +00:00
Renovate Bot 9ab2eca760 Update jest 2021-10-13 13:23:20 +00:00
Renovate Bot db6f22584c Update eslint 2021-10-09 11:19:44 +00:00
Renovate Bot b79df5fa2d Update dependency graphql to v15.6.1 2021-10-08 15:18:46 +00:00
Renovate Bot 672b5e2a1a Update dependency barrelsby to v2.3.0 2021-10-07 17:40:34 +00:00
Renovate Bot a8095edd6b Update dependency lint-staged to v11.2.0 2021-10-07 13:43:35 +00:00
Renovate Bot 1b84662e46 Update dependency eslint-plugin-jest to v24.5.2 2021-10-07 08:29:17 +00:00
Renovate Bot 255aaa2652 Update jest 2021-10-02 17:34:24 +00:00
Renovate Bot c3e2a19938 Update Node.js to v14.18.0 2021-10-01 12:16:01 +00:00
Renovate Bot 7c25ebdd65 Update eslint to v4.32.0 2021-09-30 18:46:51 +00:00
Renovate Bot a1eff91095 Update jest 2021-09-24 08:03:59 +00:00
Renovate Bot 7ace51e44f Update dependency vue-apollo to v3.0.8 2021-09-23 21:42:36 +00:00
Renovate Bot d89b0e9afd Update eslint to v4.31.2 2021-09-23 18:50:45 +00:00
Renovate Bot 1212ed8d04 Update dependency graphql to v15.6.0 2021-09-23 18:50:27 +00:00
Renovate Bot b2786ee424 Update dependency eslint-plugin-vue to v7.18.0 2021-09-20 16:24:37 +00:00
Renovate Bot b10d7ee06b Update dependency eslint-plugin-jest to v24.4.2 2021-09-20 12:09:59 +00:00
Renovate Bot fe931e4f40 Update dependency prettier to v2.4.1 2021-09-19 09:55:44 +00:00
Renovate Bot 17eaef1d9b Update eslint to v4.31.1 2021-09-16 21:02:27 +00:00
Renovate Bot 2c4da47c7f Update dependency jest to v27.2.0 2021-09-16 13:38:42 +00:00
Renovate Bot 92b9aa69d5 Update dependency typescript to v4.4.3 2021-09-14 01:31:16 +00:00
Renovate Bot fe8383adc8 Update dependency prettier to v2.4.0 2021-09-12 14:59:29 +00:00
Renovate Bot 40f5d48edf Update dependency jest to v27.1.1 2021-09-11 14:25:55 +00:00
Renovate Bot 38262bdbb9 Update eslint to v4.31.0 2021-09-09 19:51:53 +00:00
Renovate Bot 18b2dc3f80 Update dependency graphql to v15.5.3 2021-09-09 08:39:16 +00:00
Simon Garner 8ad83a4fc6 0.1.0
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2021-09-08 09:17:14 +12:00
Simon Garner 5e99a3a354 0.1.0-alpha.5
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2021-09-08 08:02:15 +12:00
Simon Garner cbe2c251fb Merge pull request #68 from madscience/fix/mutation-params
Enable mutation functions to accept all MutationOptions
2021-09-08 08:01:20 +12:00
Simon Garner ce94951550 Simplify overriding onError with params 2021-09-08 07:59:34 +12:00
Simon Garner f1969bc88c Enable mutation functions to accept all MutationOptions
The apollo client mutate() function accepts additional parameters (`optimisticResponse`, `update`, etc) that were not supported by the generated mutation operation functions before. Now those parameters will all be passed through.
2021-09-08 07:55:43 +12:00
Simon Garner 7be078995e 0.1.0-alpha.4
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2021-09-07 07:56:22 +12:00
Simon Garner f8b9bbd403 Add missing types for throttle and debounce in query options
See https://github.com/vuejs/vue-apollo/issues/335
2021-09-07 07:55:55 +12:00
Simon Garner 656eef7bcd 0.1.0-alpha.3
Build / dependencies (push) Has been cancelled
Build / lint (push) Has been cancelled
Build / build (push) Has been cancelled
Build / test (push) Has been cancelled
2021-09-06 12:10:00 +12:00
Madbot 6326ec8211 Fix code style issues with Prettier 2021-09-06 12:03:18 +12:00
Simon Garner 512eb9328b fix type conflicts with GraphQLError.message 2021-09-06 12:03:18 +12:00
Renovate Bot 8f4c8cd88f Update dependency typescript to v4.4.2 2021-09-06 12:03:18 +12:00
Madbot 0f312478bc Fix code style issues with Prettier 2021-09-06 11:15:48 +12:00
Renovate Bot b022822a97 Update dependency prettier to v2.3.2 2021-09-06 11:15:48 +12:00
Simon Garner ee396004a5 Rename test workflow -> build 2021-09-06 10:55:30 +12:00
Simon Garner 2077acddcb Use lint action with automatic fixes in CI 2021-09-06 10:55:10 +12:00
Simon Garner e34cfec074 Reformat with prettier 2021-09-06 10:52:12 +12:00
Simon Garner 595733435b Add format script 2021-09-06 10:52:12 +12:00
Simon Garner e610d9dff0 Add prettier ignore file 2021-09-06 10:52:12 +12:00
Simon Garner f5b28b0dc0 Remove eslint-plugin-prettier 2021-09-06 10:52:12 +12:00
Renovate Bot c8f8c6c7b5 Update eslint 2021-09-06 10:52:12 +12:00
Simon Garner 6ce30d8063 Merge pull request #67 from madscience/decorator
Add SmartQuery decorator
2021-09-06 10:25:47 +12:00
Simon Garner c489613d12 Add credits to README 2021-09-06 10:15:51 +12:00
Simon Garner e835aac336 Improve grammar 2021-09-06 10:13:42 +12:00
Simon Garner a318b10e97 0.1.0-alpha.2
Test / dependencies (push) Has been cancelled
Test / lint (push) Has been cancelled
Test / build (push) Has been cancelled
Test / test (push) Has been cancelled
2021-09-06 09:46:05 +12:00
Simon Garner 1ca08f363c Type loadingKey query option as being a key of the component 2021-09-06 09:45:42 +12:00
Simon Garner 0d68177297 0.1.0-alpha.1 2021-09-05 16:25:52 +12:00
Simon Garner 47a9363624 Remove --passWithNoTests
We have a test now!
2021-09-05 16:25:52 +12:00
Simon Garner 02a95b0068 Simplify headings in README 2021-09-05 16:25:52 +12:00
Simon Garner 5f77e78dce Add usage instructions to README.md 2021-09-05 16:25:52 +12:00
Simon Garner a55c4df8ac Keep empty test directory 2021-09-05 16:25:51 +12:00
Simon Garner ffe674e179 fix lint 2021-09-05 16:25:51 +12:00
Simon Garner 5316dffc79 Don't need to worry about test/.results directory any more 2021-09-05 16:25:51 +12:00
Simon Garner 2c102ffd86 Revert "Run tsc build as part of test script"
This reverts commit b5ebe6cdf5.
2021-09-05 16:25:51 +12:00
Simon Garner 653651af9e Remove example test file 2021-09-05 16:25:51 +12:00
Simon Garner 2579221ef3 Add SmartQuery decorator tests 2021-09-05 16:25:51 +12:00
Simon Garner 1671a2a641 Add VueApolloSmartQueryOptionsFunction type 2021-09-05 16:25:51 +12:00
Simon Garner 271af35ff3 Remove vue-jest, use ts-jest only 2021-09-05 16:25:51 +12:00
Simon Garner 38efa7f5fd Run tsc build as part of test script 2021-09-05 16:25:50 +12:00
Simon Garner a184514f2c Remove jest-html-reporters 2021-09-05 16:25:50 +12:00
Simon Garner 7a79a5c1fa Add test for types and decorator 2021-09-05 16:25:50 +12:00
Simon Garner 4d55c37949 Add SmartQuery decorator 2021-09-05 16:25:50 +12:00
Simon Garner 62e5db0159 Add vue-class-component to optionalDependencies 2021-09-05 16:25:50 +12:00
Renovate Bot efe3394cc7 Update Node.js to v14.17.6 2021-09-03 17:34:00 +00:00
Renovate Bot 631f1c8836 Update eslint to v4.30.0 2021-09-02 18:53:02 +00:00
Renovate Bot b0060fa347 Update dependency graphql to v15.5.2 2021-09-02 18:52:21 +00:00
Renovate Bot 51af6f30e4 Update dependency jest to v27.1.0 2021-08-30 13:07:11 +00:00
Renovate Bot 0325a5bd2e Update eslint 2021-08-30 10:02:39 +00:00
Renovate Bot 46569adf84 Update dependency husky to v7.0.2 2021-08-28 04:50:07 +00:00
Renovate Bot 1ada9125b7 Update dependency ts-jest to v27.0.5 2021-08-20 09:49:20 +00:00
Renovate Bot 0a260bd78e Update eslint to v4.29.2 2021-08-19 19:38:49 +00:00
Renovate Bot f9415e58ba Update dependency @types/jest to v27 2021-08-16 02:10:14 +00:00
Renovate Bot 1abd6285a2 Update Node.js to v14.17.5 2021-08-14 17:47:36 +00:00
Renovate Bot 93d1f2b3fb Update eslint 2021-08-13 14:48:41 +00:00
Renovate Bot 3baa30e4b8 Update dependency lint-staged to v11.1.2 2021-08-09 12:15:20 +00:00
Renovate Bot b76d2b89f8 Update eslint 2021-08-06 05:18:24 +00:00
29 changed files with 13741 additions and 6049 deletions
+1 -6
View File
@@ -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
-18
View File
@@ -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
+10 -12
View File
@@ -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 }}
+1 -1
View File
@@ -1 +1 @@
14.17.4
16.16.0
+13
View File
@@ -0,0 +1,13 @@
# Ignore workflows
.github
# Node modules
node_modules
# Test results
test/.results
test/.coverage
# IDE
.idea
.vscode
+154 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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'],
};
+12670 -5513
View File
File diff suppressed because it is too large Load Diff
+34 -40
View File
@@ -1,25 +1,26 @@
{
"name": "vue-apollo-smart-ops",
"version": "0.0.4",
"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",
"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,58 +30,51 @@
"lodash.isplainobject": "^4.0",
"lodash.mapvalues": "^4.6"
},
"optionalDependencies": {
"vue-class-component": "^7.2"
},
"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": "26.0.24",
"@types/lodash.isplainobject": "4.0.6",
"@types/lodash.mapvalues": "4.6.6",
"@typescript-eslint/eslint-plugin": "4.28.5",
"@typescript-eslint/parser": "4.28.5",
"@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.31.0",
"eslint-config-prettier": "7.2.0",
"eslint-plugin-import": "2.23.4",
"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.0",
"eslint-plugin-promise": "4.3.1",
"eslint-plugin-vue": "7.14.0",
"graphql": "15.5.1",
"husky": "7.0.1",
"jest": "27.0.6",
"jest-html-reporters": "2.1.6",
"lint-staged": "11.1.1",
"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.4",
"typescript": "4.2.4",
"ts-jest": "27.1.5",
"typescript": "4.7.4",
"vue": "2.6.14",
"vue-apollo": "3.0.7",
"vue-jest": "3.0.7"
"vue-apollo": "3.1.0",
"vue-class-component": "7.2.6",
"vue-property-decorator": "9.1.2"
},
"engines": {
"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
View File
@@ -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"
}
]
}
-219
View File
@@ -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;
}
}
+285
View File
@@ -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),
}),
]),
}),
);
});
});
+18
View File
@@ -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;
});
}
+5
View File
@@ -0,0 +1,5 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from './SmartQuery';
+50
View File
@@ -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);
}
}
+34
View File
@@ -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);
};
+8
View File
@@ -0,0 +1,8 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from './ApolloErrorHandlerResult';
export * from './handleApolloError';
export * from './processApolloError';
export * from './types';
+213
View File
@@ -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: [] };
}
+87
View File
@@ -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;
-25
View File
@@ -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,
};
};
+2 -2
View File
@@ -2,9 +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
View File
@@ -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,
);
+34 -15
View File
@@ -1,39 +1,58 @@
import { VueApolloQueryDefinition, ErrorHandler } from 'vue-apollo/types/options';
import { ApolloError, OperationVariables } from 'apollo-client';
import { DocumentNode } from 'graphql';
import { ErrorHandler, VueApolloQueryDefinition } from 'vue-apollo/types/options';
import { Vue } from 'vue/types/vue';
import { ApolloOperationErrorHandlerFunction } from './types';
import { ApolloOperationErrorHandlerFunction } from './error';
import { OverrideAllThis, SubscribeToMoreOptionsPatched } from './types';
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 +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
View File
@@ -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
View File
@@ -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;
View File
+4 -13
View File
@@ -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"]
}