From fe4b7bcc455b71981e4ed12e292f12145895da81 Mon Sep 17 00:00:00 2001 From: Javier Toledo Date: Wed, 25 Oct 2023 22:18:23 +0100 Subject: [PATCH 1/3] Removed deprecated packages related to graphql subscriptions --- common/config/rush/pnpm-lock.yaml | 126 ++++++++---------- packages/application-tester/package.json | 3 +- .../application-tester/src/graphql-helper.ts | 109 +++------------ packages/framework-core/package.json | 4 +- .../fixtures/cart-demo/package.json | 2 +- .../end-to-end/subscriptions.integration.ts | 86 +++++------- .../framework-integration-tests/package.json | 3 +- packages/framework-types/package.json | 5 +- .../src/graphql-websocket-messages.ts | 4 - 9 files changed, 107 insertions(+), 235 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 2ec8a9d5b..f0854f4a9 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -26,26 +26,24 @@ importers: eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 fast-check: 2.17.0 - graphql: ^16.6.0 + graphql: ^16.8.1 jsonwebtoken: 9.0.1 prettier: 2.3.0 rimraf: ^5.0.0 sinon: 9.2.3 sinon-chai: 3.5.0 - subscriptions-transport-ws: 0.11.0 tslib: ^2.4.0 typescript: 4.7.4 ws: 8.12.0 dependencies: - '@apollo/client': 3.7.13_fjknlyikqnbxo2aiqib2xva2wu + '@apollo/client': 3.7.13_graphql@16.8.1 '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 '@types/sinon': 10.0.0 cross-fetch: 3.1.5 - graphql: 16.6.0 + graphql: 16.8.1 jsonwebtoken: 9.0.1 sinon: 9.2.3 - subscriptions-transport-ws: 0.11.0_graphql@16.6.0 tslib: 2.5.0 ws: 8.12.0 devDependencies: @@ -277,7 +275,7 @@ importers: eslint-plugin-unicorn: ~44.0.2 faker: 5.1.0 fp-ts: ^2.11.0 - graphql: ^16.6.0 + graphql: ^16.8.1 graphql-scalars: ^1.17.0 graphql-subscriptions: 2.0.0 inflected: 2.1.0 @@ -302,8 +300,8 @@ importers: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 fp-ts: 2.14.0 - graphql-scalars: 1.21.3_graphql@16.6.0 - graphql-subscriptions: 2.0.0_graphql@16.6.0 + graphql-scalars: 1.21.3_graphql@16.8.1 + graphql-subscriptions: 2.0.0_graphql@16.8.1 inflected: 2.1.0 iterall: 1.3.0 jsonwebtoken: 9.0.1 @@ -335,7 +333,7 @@ importers: eslint-plugin-prettier: 3.4.0_uyy4h6aa7bacputuojct3xmumq eslint-plugin-unicorn: 44.0.2_eslint@8.39.0 faker: 5.1.0 - graphql: 16.6.0 + graphql: 16.8.1 mocha: 10.2.0 mock-jwks: 1.0.3_nock@11.8.2 nock: 11.8.2 @@ -394,7 +392,7 @@ importers: express-unless: 2.1.3 faker: 5.1.0 graphology-types: ^0.24.0 - graphql: ^16.6.0 + graphql: ^16.8.1 ink: ^3.0.5 jsonwebtoken: 9.0.1 jwks-rsa: 3.0.1 @@ -409,7 +407,6 @@ importers: serverless: 3.8.0 serverless-artillery: 0.5.2 sinon: 9.2.3 - subscriptions-transport-ws: 0.11.0 ts-node: ^10.9.1 ts-patch: 2.0.2 tslib: ^2.4.0 @@ -424,10 +421,10 @@ importers: '@effect-ts/core': 0.60.5 aws-sdk: 2.853.0 express-unless: 2.1.3 - graphql: 16.6.0 + graphql: 16.8.1 tslib: 2.5.0 devDependencies: - '@apollo/client': 3.7.13_jlqrawpxktjc7hvrl6agom32ae + '@apollo/client': 3.7.13_ez4pxv3kdammteum6qmsmtbq5e '@boostercloud/application-tester': link:../application-tester '@boostercloud/cli': link:../cli '@boostercloud/eslint-config': link:../../tools/eslint-config @@ -477,7 +474,6 @@ importers: serverless: 3.8.0 serverless-artillery: 0.5.2 sinon: 9.2.3 - subscriptions-transport-ws: 0.11.0_graphql@16.6.0 ts-node: 10.9.1_xpss65pzqvfdcnzjlkstkx6toy ts-patch: 2.0.2_typescript@4.7.4 typescript: 4.7.4 @@ -1065,7 +1061,7 @@ importers: eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 fast-check: 2.17.0 - graphql: ^16.6.0 + graphql: ^16.8.1 mocha: 10.2.0 nyc: ^15.1.0 prettier: 2.3.0 @@ -1100,7 +1096,7 @@ importers: eslint-plugin-prettier: 3.4.0_uyy4h6aa7bacputuojct3xmumq eslint-plugin-unicorn: 44.0.2_eslint@8.39.0 fast-check: 2.17.0 - graphql: 16.6.0 + graphql: 16.8.1 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 @@ -1192,7 +1188,7 @@ packages: '@jridgewell/trace-mapping': 0.3.18 dev: true - /@apollo/client/3.7.13_fjknlyikqnbxo2aiqib2xva2wu: + /@apollo/client/3.7.13_ez4pxv3kdammteum6qmsmtbq5e: resolution: {integrity: sha512-wi63WnO2mhb6uHGB/8x1qIOL4ZtZocrxdHS0VBQ9KwBDkwoP/TdVVgZ29J2WkiAPmJ0SK07ju4R2AjHor1gPxQ==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -1210,24 +1206,24 @@ packages: subscriptions-transport-ws: optional: true dependencies: - '@graphql-typed-document-node/core': 3.2.0_graphql@16.6.0 + '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 '@wry/context': 0.7.1 '@wry/equality': 0.5.4 '@wry/trie': 0.3.2 - graphql: 16.6.0 - graphql-tag: 2.12.6_graphql@16.6.0 + graphql: 16.8.1 + graphql-tag: 2.12.6_graphql@16.8.1 hoist-non-react-statics: 3.3.2 optimism: 0.16.2 prop-types: 15.8.1 + react: 17.0.2 response-iterator: 0.2.6 - subscriptions-transport-ws: 0.11.0_graphql@16.6.0 symbol-observable: 4.0.0 ts-invariant: 0.10.3 tslib: 2.5.0 zen-observable-ts: 1.2.5 - dev: false + dev: true - /@apollo/client/3.7.13_jlqrawpxktjc7hvrl6agom32ae: + /@apollo/client/3.7.13_graphql@16.8.1: resolution: {integrity: sha512-wi63WnO2mhb6uHGB/8x1qIOL4ZtZocrxdHS0VBQ9KwBDkwoP/TdVVgZ29J2WkiAPmJ0SK07ju4R2AjHor1gPxQ==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -1245,23 +1241,21 @@ packages: subscriptions-transport-ws: optional: true dependencies: - '@graphql-typed-document-node/core': 3.2.0_graphql@16.6.0 + '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 '@wry/context': 0.7.1 '@wry/equality': 0.5.4 '@wry/trie': 0.3.2 - graphql: 16.6.0 - graphql-tag: 2.12.6_graphql@16.6.0 + graphql: 16.8.1 + graphql-tag: 2.12.6_graphql@16.8.1 hoist-non-react-statics: 3.3.2 optimism: 0.16.2 prop-types: 15.8.1 - react: 17.0.2 response-iterator: 0.2.6 - subscriptions-transport-ws: 0.11.0_graphql@16.6.0 symbol-observable: 4.0.0 ts-invariant: 0.10.3 tslib: 2.5.0 zen-observable-ts: 1.2.5 - dev: true + dev: false /@aws-cdk/assets/1.199.0_6t5bexudk3vtq7zhe7acxljz2e: resolution: {integrity: sha512-HqI86WqJjkUpbCya8aX2Dk8Me8K5a4LdpSlVOEzzLhqN8X0wspad/hsnyQ8X1qku+N5k5rpPq5JyHUQaSAoB1A==} @@ -1525,7 +1519,7 @@ packages: '@aws-cdk/aws-codecommit': 1.199.0_u6wgonek7tj4xuwvr3d2ei6crq '@aws-cdk/aws-codestarnotifications': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu '@aws-cdk/aws-ec2': 1.199.0_ylylsu27pdmlfxyxktlluxtkr4 - '@aws-cdk/aws-ecr': 1.199.0_5lpmbvgigeswzbugyujlevszcq + '@aws-cdk/aws-ecr': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-ecr-assets': 1.199.0_u6wgonek7tj4xuwvr3d2ei6crq '@aws-cdk/aws-events': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi '@aws-cdk/aws-iam': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu @@ -1533,7 +1527,7 @@ packages: '@aws-cdk/aws-logs': 1.199.0_tqi77pcvvujtgay5663ykqn7wy '@aws-cdk/aws-s3': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-s3-assets': 1.199.0_tqi77pcvvujtgay5663ykqn7wy - '@aws-cdk/aws-secretsmanager': 1.199.0_uxypjio4ejtfqgxognd5fibs2q + '@aws-cdk/aws-secretsmanager': 1.199.0_maqnqwhn36fygp3z4rdnivbxii '@aws-cdk/core': 1.199.0_kscyon7amn7dglog7cugnqvkwm '@aws-cdk/region-info': 1.199.0 constructs: 3.4.293 @@ -1700,7 +1694,7 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/assets': 1.199.0_6t5bexudk3vtq7zhe7acxljz2e - '@aws-cdk/aws-ecr': 1.199.0_5lpmbvgigeswzbugyujlevszcq + '@aws-cdk/aws-ecr': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-iam': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu '@aws-cdk/aws-s3': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/core': 1.199.0_kscyon7amn7dglog7cugnqvkwm @@ -1710,7 +1704,7 @@ packages: - '@aws-cdk/aws-events' dev: false - /@aws-cdk/aws-ecr/1.199.0_5lpmbvgigeswzbugyujlevszcq: + /@aws-cdk/aws-ecr/1.199.0_wim6pvar6pmwiq3fs3ksmix5ru: resolution: {integrity: sha512-C4VG9uRf8UD/cNitVvYaQvF9zKwgWZoNLf43RaUrMEpo4Q/KE3/KilYBG8lsza8B7f4yjYRey5iOpydKE68kYg==} engines: {node: '>= 14.15.0'} peerDependencies: @@ -1721,8 +1715,11 @@ packages: dependencies: '@aws-cdk/aws-events': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi '@aws-cdk/aws-iam': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu + '@aws-cdk/aws-kms': 1.199.0_iumdymv27iwprkm3rzoqxlpuia '@aws-cdk/core': 1.199.0_kscyon7amn7dglog7cugnqvkwm constructs: 3.4.293 + transitivePeerDependencies: + - '@aws-cdk/cx-api' dev: false /@aws-cdk/aws-ecs/1.199.0_7m5azgjywxpgdeoosvoxrcdts4: @@ -1743,7 +1740,7 @@ packages: '@aws-cdk/aws-certificatemanager': 1.199.0_aklsbzsp6i2n6pzp4sxy6hufne '@aws-cdk/aws-cloudwatch': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi '@aws-cdk/aws-ec2': 1.199.0_ylylsu27pdmlfxyxktlluxtkr4 - '@aws-cdk/aws-ecr': 1.199.0_5lpmbvgigeswzbugyujlevszcq + '@aws-cdk/aws-ecr': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-ecr-assets': 1.199.0_u6wgonek7tj4xuwvr3d2ei6crq '@aws-cdk/aws-elasticloadbalancing': 1.199.0_ehdkigggl2baqdi4l6p7upw4f4 '@aws-cdk/aws-elasticloadbalancingv2': 1.199.0_74oizvoelbxgex3gbujl2xzm54 @@ -1755,7 +1752,7 @@ packages: '@aws-cdk/aws-route53-targets': 1.199.0_6qn3q4quwxpkjgl3z2r2rmaqqi '@aws-cdk/aws-s3': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-s3-assets': 1.199.0_tqi77pcvvujtgay5663ykqn7wy - '@aws-cdk/aws-secretsmanager': 1.199.0_uxypjio4ejtfqgxognd5fibs2q + '@aws-cdk/aws-secretsmanager': 1.199.0_maqnqwhn36fygp3z4rdnivbxii '@aws-cdk/aws-servicediscovery': 1.199.0_4axszbdsnc7kzhsa3r5g56z4bu '@aws-cdk/aws-sns': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-sqs': 1.199.0_iumdymv27iwprkm3rzoqxlpuia @@ -2001,7 +1998,7 @@ packages: '@aws-cdk/aws-lambda': 1.199.0_5pbncl2no5vqinyo3n2ekkob5q '@aws-cdk/aws-s3': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-s3-notifications': 1.199.0_fufarp47blk4okwshjegj2wjg4 - '@aws-cdk/aws-secretsmanager': 1.199.0_uxypjio4ejtfqgxognd5fibs2q + '@aws-cdk/aws-secretsmanager': 1.199.0_maqnqwhn36fygp3z4rdnivbxii '@aws-cdk/aws-sns': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-sns-subscriptions': 1.199.0_x7skkdpav5hf4ncc76dwztyszi '@aws-cdk/aws-sqs': 1.199.0_iumdymv27iwprkm3rzoqxlpuia @@ -2029,7 +2026,7 @@ packages: '@aws-cdk/aws-cloudwatch': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi '@aws-cdk/aws-codeguruprofiler': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi '@aws-cdk/aws-ec2': 1.199.0_ylylsu27pdmlfxyxktlluxtkr4 - '@aws-cdk/aws-ecr': 1.199.0_5lpmbvgigeswzbugyujlevszcq + '@aws-cdk/aws-ecr': 1.199.0_wim6pvar6pmwiq3fs3ksmix5ru '@aws-cdk/aws-ecr-assets': 1.199.0_u6wgonek7tj4xuwvr3d2ei6crq '@aws-cdk/aws-efs': 1.199.0_ylylsu27pdmlfxyxktlluxtkr4 '@aws-cdk/aws-events': 1.199.0_wcptolxmxi6sy3vjqhvgbrrnvi @@ -2226,7 +2223,7 @@ packages: constructs: 3.4.293 dev: false - /@aws-cdk/aws-secretsmanager/1.199.0_uxypjio4ejtfqgxognd5fibs2q: + /@aws-cdk/aws-secretsmanager/1.199.0_maqnqwhn36fygp3z4rdnivbxii: resolution: {integrity: sha512-Dj0+q7I9xRwg1hHowrHb9rxmicDGZVmQixFaFuBdsS5zNfBNdC6WJGWhDddJDZIPclip06fXBm/by4+l4XUpNw==} engines: {node: '>= 14.15.0'} peerDependencies: @@ -2236,12 +2233,18 @@ packages: '@aws-cdk/cx-api': 1.199.0 constructs: ^3.3.69 dependencies: + '@aws-cdk/aws-ec2': 1.199.0_ylylsu27pdmlfxyxktlluxtkr4 '@aws-cdk/aws-iam': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu + '@aws-cdk/aws-kms': 1.199.0_iumdymv27iwprkm3rzoqxlpuia '@aws-cdk/aws-lambda': 1.199.0_5pbncl2no5vqinyo3n2ekkob5q '@aws-cdk/aws-sam': 1.199.0_xwfh4icwyvj4zfjhzlqde6qllu '@aws-cdk/core': 1.199.0_kscyon7amn7dglog7cugnqvkwm '@aws-cdk/cx-api': 1.199.0 constructs: 3.4.293 + transitivePeerDependencies: + - '@aws-cdk/assets' + - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3' dev: false /@aws-cdk/aws-servicediscovery/1.199.0_4axszbdsnc7kzhsa3r5g56z4bu: @@ -3068,12 +3071,12 @@ packages: resolution: {integrity: sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@graphql-typed-document-node/core/3.2.0_graphql@16.6.0: + /@graphql-typed-document-node/core/3.2.0_graphql@16.8.1: resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: 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 || ^17.0.0 dependencies: - graphql: 16.6.0 + graphql: 16.8.1 /@humanwhocodes/config-array/0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} @@ -4309,9 +4312,6 @@ packages: - debug dev: true - /backo2/1.0.2: - resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} - /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -5785,9 +5785,6 @@ packages: es5-ext: 0.10.62 dev: true - /eventemitter3/3.1.2: - resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} - /events/1.1.1: resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} engines: {node: '>=0.4.x'} @@ -6467,36 +6464,36 @@ packages: graphology-types: 0.21.2 obliterator: 2.0.4 - /graphql-scalars/1.21.3_graphql@16.6.0: + /graphql-scalars/1.21.3_graphql@16.8.1: resolution: {integrity: sha512-QLWw3BHmqHZMp9JeYmPpjq7JT9aw/H8TpwmWKJEuMSE3+O7Xe7TduQbOLFzbs1q9UxX6CVkc0O1JO/YfkP/pAw==} engines: {node: '>=10'} peerDependencies: 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 dependencies: - graphql: 16.6.0 + graphql: 16.8.1 tslib: 2.5.0 dev: false - /graphql-subscriptions/2.0.0_graphql@16.6.0: + /graphql-subscriptions/2.0.0_graphql@16.8.1: resolution: {integrity: sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA==} peerDependencies: graphql: ^15.7.2 || ^16.0.0 dependencies: - graphql: 16.6.0 + graphql: 16.8.1 iterall: 1.3.0 dev: false - /graphql-tag/2.12.6_graphql@16.6.0: + /graphql-tag/2.12.6_graphql@16.8.1: resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 dependencies: - graphql: 16.6.0 + graphql: 16.8.1 tslib: 2.5.0 - /graphql/16.6.0: - resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} + /graphql/16.8.1: + resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} /has-bigints/1.0.2: @@ -7081,6 +7078,7 @@ packages: /iterall/1.3.0: resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} + dev: false /jackspeak/2.2.0: resolution: {integrity: sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==} @@ -9549,22 +9547,6 @@ packages: peek-readable: 4.1.0 dev: true - /subscriptions-transport-ws/0.11.0_graphql@16.6.0: - resolution: {integrity: sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==} - deprecated: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md - peerDependencies: - graphql: ^15.7.2 || ^16.0.0 - dependencies: - backo2: 1.0.2 - eventemitter3: 3.1.2 - graphql: 16.6.0 - iterall: 1.3.0 - symbol-observable: 1.2.0 - ws: 7.5.9 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - /superagent/7.1.6_supports-color@8.1.1: resolution: {integrity: sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==} engines: {node: '>=6.4.0 <13 || >=14'} @@ -9621,10 +9603,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /symbol-observable/1.2.0: - resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} - engines: {node: '>=0.10.0'} - /symbol-observable/4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} diff --git a/packages/application-tester/package.json b/packages/application-tester/package.json index 0814f0e4e..9928dafd3 100644 --- a/packages/application-tester/package.json +++ b/packages/application-tester/package.json @@ -38,9 +38,8 @@ "@apollo/client": "3.7.13", "@boostercloud/framework-types": "workspace:^1.20.0", "cross-fetch": "3.1.5", - "graphql": "^16.6.0", + "graphql": "^16.8.1", "jsonwebtoken": "9.0.1", - "subscriptions-transport-ws": "0.11.0", "tslib": "^2.4.0", "ws": "8.12.0", "@types/sinon": "10.0.0", diff --git a/packages/application-tester/src/graphql-helper.ts b/packages/application-tester/src/graphql-helper.ts index f4001b82e..c17cf135d 100644 --- a/packages/application-tester/src/graphql-helper.ts +++ b/packages/application-tester/src/graphql-helper.ts @@ -1,16 +1,6 @@ -import { - ApolloClient, - ApolloClientOptions, - ApolloLink, - HttpLink, - InMemoryCache, - NormalizedCacheObject, - split, -} from '@apollo/client' +import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, NormalizedCacheObject, split } from '@apollo/client' import { WebSocketLink } from '@apollo/client/link/ws' import fetch from 'cross-fetch' -import * as WebSocket from 'ws' -import { SubscriptionClient } from 'subscriptions-transport-ws' import { ProviderTestHelper } from './provider-test-helper' import { getMainDefinition } from '@apollo/client/utilities' @@ -31,23 +21,31 @@ export class GraphQLHelper { }) } - /** - * IMPORTANT: After using this "DisconnectableApolloClient", you must call ".disconnect()" to close the socket. Otherwise - * it will keep waiting for messages forever - */ - public async clientWithSubscriptions(authToken?: AuthToken): Promise { - const subscriptionClient: SubscriptionClient = await this.subscriptionsClient(authToken) + public async clientWithSubscriptions(authToken?: AuthToken): Promise> { + const wsLink = new WebSocketLink({ + uri: this.providerTestHelper.outputs.websocketURL, + options: { + reconnect: true, + connectionParams: () => { + if (authToken) { + const token = typeof authToken == 'function' ? authToken() : authToken + return { Authorization: 'Bearer ' + token } + } + return {} + }, + }, + }) const link = split( ({ query }) => { const definition = getMainDefinition(query) return definition.kind === 'OperationDefinition' && definition.operation === 'subscription' }, - new WebSocketLink(subscriptionClient), + wsLink, this.getAuthLink(authToken).concat(this.getApolloHTTPLink()) ) - return new DisconnectableApolloClient(subscriptionClient, { + return new ApolloClient({ cache: new InMemoryCache(), link: link, defaultOptions: { @@ -74,77 +72,4 @@ export class GraphQLHelper { return forward(operation) }) } - - private async subscriptionsClient(authToken?: AuthToken): Promise { - return new Promise((resolve, reject) => { - const subscriptionClient = new SubscriptionClient( - this.providerTestHelper.outputs.websocketURL, - { - reconnect: true, - connectionParams: () => { - if (authToken) { - const token = typeof authToken == 'function' ? authToken() : authToken - return { - Authorization: 'Bearer ' + token, - } - } - return {} - }, - connectionCallback: (err?: any) => { - if (err) { - reject(err) - return - } - resolve(subscriptionClient) - }, - }, - class MyWebSocket extends WebSocket { - public constructor(url: string, protocols?: string | string[]) { - super(url, protocols) - - this.addListener('open', (): void => { - console.debug('[GraphQL socket] on open') - }) - this.addListener('ping', (): void => { - console.debug('[GraphQL socket] on "ping"') - }) - this.addListener('pong', (): void => { - console.debug('[GraphQL socket] on "pong"') - }) - this.addListener('message', (data: WebSocket.Data): void => { - console.debug('[GraphQL socket] on message: ', data) - }) - this.addListener('close', (code: number, message: string): void => { - console.debug('[GraphQL socket] on close: ', code, message) - }) - this.addListener('error', (err: Error): void => { - console.debug('[GraphQL socket] on error: ', err.message) - }) - } - } - ) - }) - } -} - -export class DisconnectableApolloClient extends ApolloClient { - constructor( - private readonly subscriptionClient: SubscriptionClient, - options: ApolloClientOptions - ) { - super(options) - } - - public reconnect(): Promise { - const reconnectPromise = new Promise((resolve) => { - this.subscriptionClient.onReconnected(resolve) - }) - this.subscriptionClient.close(false) - return reconnectPromise - } - - public disconnect(): void { - this.subscriptionClient.close() - this.stop() - } } diff --git a/packages/framework-core/package.json b/packages/framework-core/package.json index 8b283cc0f..5ebf3ee72 100644 --- a/packages/framework-core/package.json +++ b/packages/framework-core/package.json @@ -33,7 +33,7 @@ "node": ">=18.0.0 <19.0.0" }, "peerDependencies": { - "graphql": "^16.6.0" + "graphql": "^16.8.1" }, "dependencies": { "@boostercloud/framework-common-helpers": "workspace:^1.20.0", @@ -84,7 +84,7 @@ "ts-node": "^10.9.1", "typescript": "4.7.4", "eslint-plugin-unicorn": "~44.0.2", - "graphql": "^16.6.0" + "graphql": "^16.8.1" }, "pnpm": { "overrides": { diff --git a/packages/framework-integration-tests/integration/fixtures/cart-demo/package.json b/packages/framework-integration-tests/integration/fixtures/cart-demo/package.json index aafb8a4c4..761fd097b 100644 --- a/packages/framework-integration-tests/integration/fixtures/cart-demo/package.json +++ b/packages/framework-integration-tests/integration/fixtures/cart-demo/package.json @@ -25,7 +25,7 @@ "@boostercloud/framework-provider-aws-infrastructure": "whatever", "ts-patch": "whatever", "@boostercloud/metadata-booster": "whatever", - "graphql": "^16.6.0" + "graphql": "^16.8.1" }, "engines": { "node": ">=18.0.0 <19.0.0" diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts index 92508833d..c7e8117ce 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts @@ -2,10 +2,9 @@ import { internet, random } from 'faker' import { expect } from '../../helper/expect' import { waitForIt } from '../../helper/sleep' import { FilterFor } from '@boostercloud/framework-types' -import { DisconnectableApolloClient } from '@boostercloud/application-tester' import { applicationUnderTest } from './setup' import { beforeHookProductId } from '../../../src/constants' -import { Observable, gql } from '@apollo/client' +import { ApolloClient, NormalizedCacheObject, Observable, gql } from '@apollo/client' describe('subscriptions', () => { let countSubscriptions: () => Promise @@ -16,12 +15,14 @@ describe('subscriptions', () => { }) describe('the "unsubscribe" operation', () => { - let client: DisconnectableApolloClient + let client: ApolloClient + before(async () => { client = await applicationUnderTest.graphql.clientWithSubscriptions() }) + after(() => { - client.disconnect() + client.stop() }) it('should delete a subscription when the client calls "unsubscribe"', async () => { @@ -44,8 +45,8 @@ describe('subscriptions', () => { describe('the "terminate" operation', () => { it('should delete all subscription of the connectionID when socket is disconnected', async () => { - const clientA = await applicationUnderTest.graphql.clientWithSubscriptions() - const clientB = await applicationUnderTest.graphql.clientWithSubscriptions() + const clientA: ApolloClient = await applicationUnderTest.graphql.clientWithSubscriptions() + const clientB: ApolloClient = await applicationUnderTest.graphql.clientWithSubscriptions() try { const originalSubscriptionsCount = await countSubscriptions() @@ -60,15 +61,15 @@ describe('subscriptions', () => { await waitForIt(countSubscriptions, (newCount) => newCount == originalSubscriptionsCount + 3) // Now we close the socket of client B and check its 2 subscriptions were deleted - clientB.disconnect() + clientB.stop() await waitForIt(countSubscriptions, (newCount) => newCount == originalSubscriptionsCount + 1) // Finally, close the socket of client A and check that we are back to the original count of subscriptions - clientA.disconnect() + clientA.stop() await waitForIt(countSubscriptions, (newCount) => newCount == originalSubscriptionsCount) } catch (e) { - clientA.disconnect() - clientB.disconnect() + clientA.stop() + clientB.stop() } }) @@ -85,42 +86,13 @@ describe('subscriptions', () => { }) }) - describe('when socket reconnects ', () => { - let clients: DisconnectableApolloClient[] - const clientCount = 2 - before(async () => { - clients = [] - for (let i = 0; i < clientCount; i++) - clients.push(await applicationUnderTest.graphql.clientWithSubscriptions()) - }) - after(() => { - clients.forEach(c => c.disconnect()) - }) - - it('keeps the same subscriptions', async () => { - const cartID = random.uuid() - const originalSubscriptionsCount = await countSubscriptions() - const observables = clients.map(c => cartSubscription(c, cartID)) - observables.forEach(o => o.subscribe(() => {})); - await waitForIt(countSubscriptions, (newCount) => newCount == originalSubscriptionsCount + clientCount) - await verifySubscriptionsActive() - await Promise.all(clients.map(c => c.reconnect())) - await verifySubscriptionsActive() - - async function verifySubscriptionsActive() { - await cartMutation(clients[0], cartID) - await expect(Promise.all(observables.map(promisifyNextSubscriptionResult))).to.eventually.be.fulfilled - } - }) - }) - describe('with filters', () => { - let client: DisconnectableApolloClient + let client: ApolloClient before(async () => { client = await applicationUnderTest.graphql.clientWithSubscriptions() }) after(() => { - client.disconnect() + client.stop() }) it('get a carts with a specific ID', async () => { @@ -228,14 +200,14 @@ describe('subscriptions', () => { describe('readmodel authorization', () => { context('with an anonymous user', () => { - let client: DisconnectableApolloClient + let client: ApolloClient beforeEach(async () => { client = await applicationUnderTest.graphql.clientWithSubscriptions() }) afterEach(() => { - client.disconnect() + client.stop() }) context('with a read model authorized for matching roles', () => { @@ -257,9 +229,9 @@ describe('subscriptions', () => { }) }) }) - + context('with a user without the required role', () => { - let loggedClient: DisconnectableApolloClient + let loggedClient: ApolloClient beforeEach(async () => { const userToken = applicationUnderTest.token.forUser(internet.email(), 'UserThatHasNoBusinesWithProducts') @@ -267,7 +239,7 @@ describe('subscriptions', () => { }) afterEach(() => { - loggedClient.disconnect() + loggedClient.stop() }) context('with a read model authorized for matching roles', () => { @@ -291,7 +263,7 @@ describe('subscriptions', () => { }) context('with a user with the required role', () => { - let loggedClient: DisconnectableApolloClient + let loggedClient: ApolloClient beforeEach(async () => { const userToken = applicationUnderTest.token.forUser(internet.email(), 'UserWithEmail') @@ -299,7 +271,7 @@ describe('subscriptions', () => { }) afterEach(() => { - loggedClient.disconnect() + loggedClient.stop() }) context('with a read model authorized for matching roles', () => { @@ -320,7 +292,7 @@ describe('subscriptions', () => { }) }) -function cartSubscription(client: DisconnectableApolloClient, cartID: string): Observable { +function cartSubscription(client: ApolloClient, cartID: string): Observable { return client.subscribe({ variables: { cartId: cartID }, query: gql` @@ -337,7 +309,7 @@ function cartSubscription(client: DisconnectableApolloClient, cartID: string): O }) } -function productSubscription(client: DisconnectableApolloClient, productId: string): Observable { +function productSubscription(client: ApolloClient, productId: string): Observable { return client.subscribe({ variables: { productId: productId }, query: gql` @@ -354,7 +326,10 @@ function productSubscription(client: DisconnectableApolloClient, productId: stri }) } -function cartFilteredSubscription(client: DisconnectableApolloClient, filter: FilterFor): Observable { +function cartFilteredSubscription( + client: ApolloClient, + filter: FilterFor +): Observable { return client.subscribe({ variables: { filter }, query: gql` @@ -372,7 +347,10 @@ function cartFilteredSubscription(client: DisconnectableApolloClient, filter: Fi }) } -function cartFilteredSingleIDSubscription(client: DisconnectableApolloClient, cartId: string): Observable { +function cartFilteredSingleIDSubscription( + client: ApolloClient, + cartId: string +): Observable { return client.subscribe({ variables: { cartId, random: 'variable' }, query: gql` @@ -400,7 +378,7 @@ function promisifyNextSubscriptionResult(observable: Observable): Promise, cartID: string, productId: string = random.uuid() ): Promise { @@ -417,7 +395,7 @@ async function cartMutation( }) } -async function productMutation(client: DisconnectableApolloClient, productId: string): Promise { +async function productMutation(client: ApolloClient, productId: string): Promise { const sku = random.uuid() await client.mutate({ variables: { diff --git a/packages/framework-integration-tests/package.json b/packages/framework-integration-tests/package.json index 815f57138..f50c27e51 100644 --- a/packages/framework-integration-tests/package.json +++ b/packages/framework-integration-tests/package.json @@ -16,7 +16,7 @@ "@boostercloud/framework-provider-local": "workspace:^1.20.0", "@boostercloud/framework-types": "workspace:^1.20.0", "aws-sdk": "2.853.0", - "graphql": "^16.6.0", + "graphql": "^16.8.1", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", "express-unless": "2.1.3" @@ -70,7 +70,6 @@ "reflect-metadata": "0.1.13", "serverless": "3.8.0", "serverless-artillery": "0.5.2", - "subscriptions-transport-ws": "0.11.0", "ts-node": "^10.9.1", "ts-patch": "2.0.2", "typescript": "4.7.4", diff --git a/packages/framework-types/package.json b/packages/framework-types/package.json index c94aef6f5..216cbaa2c 100644 --- a/packages/framework-types/package.json +++ b/packages/framework-types/package.json @@ -35,9 +35,6 @@ "engines": { "node": ">=18.0.0 <19.0.0" }, - "peerDependencies": { - "graphql": "^16.6.0" - }, "dependencies": { "tslib": "^2.4.0", "uuid": "8.3.2", @@ -70,7 +67,7 @@ "typescript": "4.7.4", "prettier": "2.3.0", "eslint-plugin-unicorn": "~44.0.2", - "graphql": "^16.6.0", + "graphql": "^16.8.1", "rimraf": "^5.0.0" }, "pnpm": { diff --git a/packages/framework-types/src/graphql-websocket-messages.ts b/packages/framework-types/src/graphql-websocket-messages.ts index 7468fd454..0a587f450 100644 --- a/packages/framework-types/src/graphql-websocket-messages.ts +++ b/packages/framework-types/src/graphql-websocket-messages.ts @@ -1,8 +1,4 @@ import { GraphQLOperation } from './envelope' -// Disable this lint rule here. In "framework-types" we only need the types of graphql, -// so we use the dependency "@types/graphql". However, this lint rule expects us to use the whole "graphql" -// dependency, which doesn't make sense for this case. -// eslint-disable-next-line import/no-extraneous-dependencies import { ExecutionResult } from 'graphql' export enum MessageTypes { From 570c940d35d7124082c9cb8cba20d88f0934980c Mon Sep 17 00:00:00 2001 From: Javier Toledo Date: Wed, 25 Oct 2023 23:40:03 +0100 Subject: [PATCH 2/3] Remove remaining traces of subscriptions-transport-ws --- common/config/rush/pnpm-lock.yaml | 6 - .../deployment/deployment.integration.ts | 4 +- website/docs/06_graphql.md | 149 +++++++++--------- website/package-lock.json | 82 +--------- website/package.json | 1 - website/src/services/apollo-service.ts | 26 +-- 6 files changed, 91 insertions(+), 177 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index f0854f4a9..980a00e01 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -1195,7 +1195,6 @@ packages: graphql-ws: ^5.5.5 react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - subscriptions-transport-ws: ^0.9.0 || ^0.11.0 peerDependenciesMeta: graphql-ws: optional: true @@ -1203,8 +1202,6 @@ packages: optional: true react-dom: optional: true - subscriptions-transport-ws: - optional: true dependencies: '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 '@wry/context': 0.7.1 @@ -1230,7 +1227,6 @@ packages: graphql-ws: ^5.5.5 react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - subscriptions-transport-ws: ^0.9.0 || ^0.11.0 peerDependenciesMeta: graphql-ws: optional: true @@ -1238,8 +1234,6 @@ packages: optional: true react-dom: optional: true - subscriptions-transport-ws: - optional: true dependencies: '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 '@wry/context': 0.7.1 diff --git a/packages/framework-integration-tests/integration/provider-specific/azure/deployment/deployment.integration.ts b/packages/framework-integration-tests/integration/provider-specific/azure/deployment/deployment.integration.ts index f35cd24e9..ad87a66a2 100644 --- a/packages/framework-integration-tests/integration/provider-specific/azure/deployment/deployment.integration.ts +++ b/packages/framework-integration-tests/integration/provider-specific/azure/deployment/deployment.integration.ts @@ -5,7 +5,7 @@ import { applicationName, checkAndGetCurrentEnv, getProviderTestHelper } from '. import { internet, random, commerce, finance } from 'faker' import { waitForIt } from '../../../helper/sleep' import { ApplicationTester } from '@boostercloud/application-tester' -import { gql } from '@apollo/client' +import { gql, ApolloClient, NormalizedCacheObject } from '@apollo/client' describe('After deployment', () => { describe('the ARM template', () => { @@ -34,7 +34,7 @@ describe('After deployment', () => { async () => { try { console.log('Performing mutation') - const client = applicationUnderTest.graphql.client(authToken) + const client: ApolloClient = applicationUnderTest.graphql.client(authToken) return await client.mutate({ variables: { sku: random.uuid(), diff --git a/website/docs/06_graphql.md b/website/docs/06_graphql.md index 87611db41..2f9311fea 100644 --- a/website/docs/06_graphql.md +++ b/website/docs/06_graphql.md @@ -919,37 +919,38 @@ One of the best clients to connect to a GraphQL API is the [Apollo](https://www. We recommend referring to the documentation of those clients to know how to use them. Here is an example of how to fully instantiate the Javascript client so that it works for queries, mutations and subscriptions: ```typescript -import { split, HttpLink } from '@apollo/client' -import { getMainDefinition } from '@apollo/client/utilities' -import { WebSocketLink } from '@apollo/client/link/ws' -import { ApolloClient, InMemoryCache } from '@apollo/client' -import { SubscriptionClient } from 'subscriptions-transport-ws' +import { split, HttpLink } from '@apollo/client'; +import { getMainDefinition } from '@apollo/client/utilities'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { ApolloClient, InMemoryCache } from '@apollo/client'; // Helper function that checks if a GraphQL operation is a subscription or not function isSubscriptionOperation({ query }) { - const definition = getMainDefinition(query) - return definition.kind === 'OperationDefinition' && definition.operation === 'subscription' + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; } // Create an HTTP link for sending queries and mutations const httpLink = new HttpLink({ uri: '', -}) +}); -// Create a SusbscriptionClient and a WebSocket link for sending subscriptions -const subscriptionClient = new SubscriptionClient('', { - reconnect: true, -}) -const wsLink = new WebSocketLink(subscriptionClient) +// Create a WebSocket link for sending subscriptions +const wsLink = new WebSocketLink({ + uri: '', + options: { + reconnect: true, + }, +}); // Combine both links so that depending on the operation, it uses one or another -const splitLink = split(isSubscriptionOperation, wsLink, httpLink) +const splitLink = split(isSubscriptionOperation, wsLink, httpLink); // Finally, create the client using the link created above const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(), -}) +}); ``` Now, we can send queries, mutations and subscriptions using the `client` instance: @@ -1033,21 +1034,20 @@ You normally won't be sending tokens in such a low-level way. GraphQL clients ha We recommend going to the specific documentation of the specific Apollo client you are using to know how to send tokens. However, the basics of this guide remains the same. Here is an example of how you would configure the Javascript/Typescript Apollo client to send the authorization token. The example is exactly the same as the one shown in the [Using Apollo clients](#using-apollo-client) section, but with the changes needed to send the token. Notice that `` and `` are obtained from the [Authentication Rocket](https://github.com/boostercloud/rocket-auth-aws-infrastructure). ```typescript -import { split, HttpLink, ApolloLink } from '@apollo/client' -import { getMainDefinition } from '@apollo/client/utilities' -import { WebSocketLink } from '@apollo/client/link/ws' -import { ApolloClient, InMemoryCache } from '@apollo/client' -import { SubscriptionClient } from 'subscriptions-transport-ws' +import { split, HttpLink, ApolloLink } from '@apollo/client'; +import { getMainDefinition } from '@apollo/client/utilities'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { ApolloClient, InMemoryCache } from '@apollo/client'; function isSubscriptionOperation({ query }) { - const definition = getMainDefinition(query) - return definition.kind === 'OperationDefinition' && definition.operation === 'subscription' + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; } // CHANGED: We now use the AuthApiEndpoint obtained by the auth rocket const httpLink = new HttpLink({ uri: '', -}) +}); // CHANGED: We create an "authLink" that modifies the operation by adding the token to the headers const authLink = new ApolloLink((operation, forward) => { @@ -1055,30 +1055,33 @@ const authLink = new ApolloLink((operation, forward) => { headers: { Authorization: 'Bearer ', }, - }) - return forward(operation) -}) + }); + return forward(operation); +}); // <-- CHANGED: Concatenate the links so that the "httpLink" receives the operation with the headers set by the "authLink" -const httpLinkWithAuth = authLink.concat(httpLink) - -const subscriptionClient = new SubscriptionClient('', { - reconnect: true, - // CHANGED: added a "connectionParam" property with a function that returns the `Authorizaiton` header containing our token - connectionParams: () => { - return { - Authorization: 'Bearer ', - } +const httpLinkWithAuth = authLink.concat(httpLink); + +// CHANGED: Create a WebSocket link for sending subscriptions +const wsLink = new WebSocketLink({ + uri: '', + options: { + reconnect: true, + // CHANGED: added a "connectionParam" property with a function that returns the `Authorization` header containing our token + connectionParams: () => { + return { + Authorization: 'Bearer ', + }; + }, }, -}) -const wsLink = new WebSocketLink(subscriptionClient) +}); -const splitLink = split(isSubscriptionOperation, wsLink, httpLinkWithAuth) // Note that we now are using "httpLinkWithAuth" +const splitLink = split(isSubscriptionOperation, wsLink, httpLinkWithAuth); // Note that we now are using "httpLinkWithAuth" const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(), -}) +}); ``` ### Refreshing tokens with Apollo clients @@ -1090,56 +1093,58 @@ There are several ways to do this. Here we show the simplest one for learning pu First, we modify the example shown in the section [Sending tokens with apollo clients](#sending-tokens-with-apollo-clients) so that the token is stored in a global variable and the Apollo links get the token from it. That variable will be updated when the user signs-in and the token is refreshed: ```typescript -import { split, HttpLink, ApolloLink } from '@apollo/client' -import { getMainDefinition } from '@apollo/client/utilities' -import { WebSocketLink } from '@apollo/client/link/ws' -import { ApolloClient, InMemoryCache } from '@apollo/client' -import { SubscriptionClient } from 'subscriptions-transport-ws' +import { split, HttpLink, ApolloLink } from '@apollo/client'; +import { getMainDefinition } from '@apollo/client/utilities'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { ApolloClient, InMemoryCache } from '@apollo/client'; -let authToken = undefined // <-- CHANGED: This variable will hold the token and will be updated everytime the token is refreshed +let authToken = undefined; // <-- No change here, this variable will hold the token and will be updated every time the token is refreshed. function isSubscriptionOperation({ query }) { - const definition = getMainDefinition(query) - return definition.kind === 'OperationDefinition' && definition.operation === 'subscription' + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; } const httpLink = new HttpLink({ uri: '', -}) +}); const authLink = new ApolloLink((operation, forward) => { if (authToken) { operation.setContext({ headers: { - Authorization: `Bearer ${authToken}`, // <-- CHANGED: We use the "authToken" global variable + Authorization: `Bearer ${authToken}`, // <-- No change here, continue using the "authToken" global variable. }, - }) + }); } - return forward(operation) -}) - -const httpLinkWithAuth = authLink.concat(httpLink) - -const subscriptionClient = new SubscriptionClient('', { - reconnect: true, - // CHANGED: added a "connectionParam" property with a function that returns the `Authorizaiton` header containing our token - connectionParams: () => { - if (authToken) { - return { - Authorization: `Bearer ${authToken}`, // <-- CHANGED: We use the "authToken" global variable + return forward(operation); +}); + +const httpLinkWithAuth = authLink.concat(httpLink); + +// CHANGED: Create a WebSocket link for sending subscriptions, and specify the connectionParams for Authorization header. +const wsLink = new WebSocketLink({ + uri: '', + options: { + reconnect: true, + connectionParams: () => { + if (authToken) { + return { + Authorization: `Bearer ${authToken}`, // <-- CHANGED: We use the "authToken" global variable. + }; } - } - return {} + return {}; + }, }, -}) -const wsLink = new WebSocketLink(subscriptionClient) +}); -const splitLink = split(isSubscriptionOperation, wsLink, httpLinkWithAuth) +const splitLink = split(isSubscriptionOperation, wsLink, httpLinkWithAuth); const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache(), -}) +}); + ``` Now, _when the user signs-in_ or _when the token is refreshed_, we need to do two things: @@ -1155,10 +1160,4 @@ Sockets are channels for two-way communication that doesn't follow the request-r For these reasons, in order to have an effective non-trivial communication through sockets, a sub-protocol is needed. It would be in charge of making both parts understand each other, share authentication tokens, matching response to the corresponding requests, etc. -The Booster WebSocket communication uses the "GraphQL over WebSocket" protocol as subprotocol. It is in charge of all the low level stuff needed to properly send subscription operations to read models and receive the corresponding data. - -You don't need to know anything about this to develop using Booster, neither in the backend side nor in the frontend side (as all the Apollo GraphQL clients uses this protocol), but it is good to know it is there to guarantee a proper communication. In case you are really curious, you can read about the protocol [here](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md). - -:::note -The WebSocket communication in Booster only supports this subprotocol, whose identifier is `graphql-ws`. For this reason, when you connect to the WebSocket provisioned by Booster, you must specify the `graphql-ws` subprotocol. If not, the connection won't succeed. -::: +You don't need to know anything about this to develop using Booster, neither in the backend side nor in the frontend side (as all the Apollo GraphQL clients use this protocol), but it's good to know it is there to guarantee a proper communication. If you are really curious, you can read about the protocol [here](https://github.com/enisdenjo/graphql-ws). \ No newline at end of file diff --git a/website/package-lock.json b/website/package-lock.json index 660aaae5c..edcc8d0c7 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -24,7 +24,6 @@ "react-dom": "^17.0.2", "react-markdown": "^8.0.5", "react-modal": "^3.16.1", - "subscriptions-transport-ws": "^0.11.0", "tailwindcss": "^3.2.4" }, "devDependencies": { @@ -33,7 +32,7 @@ "typescript": "^4.7.4" }, "engines": { - "node": ">=16.14" + "node": ">=18.0.0 <19.0.0" } }, "node_modules/@algolia/autocomplete-core": { @@ -216,8 +215,7 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0", "graphql-ws": "^5.5.5", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "graphql-ws": { @@ -228,9 +226,6 @@ }, "react-dom": { "optional": true - }, - "subscriptions-transport-ws": { - "optional": true } } }, @@ -4206,11 +4201,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" - }, "node_modules/bail": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", @@ -7698,11 +7688,6 @@ "node": ">=0.10.0" } }, - "node_modules/iterall": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, "node_modules/jest-util": { "version": "29.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.0.tgz", @@ -12245,35 +12230,6 @@ "postcss": "^8.2.15" } }, - "node_modules/subscriptions-transport-ws": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz", - "integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==", - "deprecated": "The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md", - "dependencies": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependencies": { - "graphql": "^15.7.2 || ^16.0.0" - } - }, - "node_modules/subscriptions-transport-ws/node_modules/eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "node_modules/subscriptions-transport-ws/node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -17057,11 +17013,6 @@ "@babel/helper-define-polyfill-provider": "^0.3.3" } }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" - }, "bail": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", @@ -19551,11 +19502,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, - "iterall": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, "jest-util": { "version": "29.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.0.tgz", @@ -22688,30 +22634,6 @@ "postcss-selector-parser": "^6.0.4" } }, - "subscriptions-transport-ws": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz", - "integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==", - "requires": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - }, - "dependencies": { - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - } - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/website/package.json b/website/package.json index 47d20bd3d..4017175c2 100644 --- a/website/package.json +++ b/website/package.json @@ -31,7 +31,6 @@ "react-dom": "^17.0.2", "react-markdown": "^8.0.5", "react-modal": "^3.16.1", - "subscriptions-transport-ws": "^0.11.0", "tailwindcss": "^3.2.4" }, "devDependencies": { diff --git a/website/src/services/apollo-service.ts b/website/src/services/apollo-service.ts index 4c8e200a9..0bcfd0d84 100644 --- a/website/src/services/apollo-service.ts +++ b/website/src/services/apollo-service.ts @@ -1,32 +1,32 @@ -import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, NormalizedCacheObject, split } from '@apollo/client' -import { WebSocketLink } from '@apollo/client/link/ws' -import { getMainDefinition } from '@apollo/client/utilities' -import { SubscriptionClient } from 'subscriptions-transport-ws' +import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, NormalizedCacheObject, split } from '@apollo/client'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { getMainDefinition } from '@apollo/client/utilities'; export class ApolloService { static initClient(httpUri: string, wsUri: string): ApolloClient { const httpLink = new HttpLink({ uri: httpUri, - }) + }); - const wsLink = new WebSocketLink( - new SubscriptionClient(wsUri, { + const wsLink = new WebSocketLink({ + uri: wsUri, + options: { reconnect: true, - }) - ) + }, + }); const splitLink = split( ({ query }) => { - const definition = getMainDefinition(query) - return definition.kind === 'OperationDefinition' && definition.operation === 'subscription' + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; }, wsLink, httpLink - ) + ); return new ApolloClient({ cache: new InMemoryCache(), link: ApolloLink.from([splitLink]), - }) + }); } } From 4609a1dc0aa866afffd4a0742aa53b20ecd1d000 Mon Sep 17 00:00:00 2001 From: Javier Toledo Date: Tue, 31 Oct 2023 16:25:38 +0000 Subject: [PATCH 3/3] Switch subprotocol references --- packages/framework-core/test/booster-graphql-dispatcher.test.ts | 2 +- packages/framework-types/src/graphql-websocket-messages.ts | 2 +- upgrade-v2.md | 1 + website/docs/06_graphql.md | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/framework-core/test/booster-graphql-dispatcher.test.ts b/packages/framework-core/test/booster-graphql-dispatcher.test.ts index db9a28b12..2195491b8 100644 --- a/packages/framework-core/test/booster-graphql-dispatcher.test.ts +++ b/packages/framework-core/test/booster-graphql-dispatcher.test.ts @@ -99,7 +99,7 @@ describe('the `BoosterGraphQLDispatcher`', () => { await dispatcher.dispatch({}) expect(config.provider.graphQL.handleResult).to.have.been.calledOnceWithExactly(null, { - 'Sec-WebSocket-Protocol': 'graphql-ws', + 'Sec-WebSocket-Protocol': 'graphql-transport-ws', }) }) }) diff --git a/packages/framework-types/src/graphql-websocket-messages.ts b/packages/framework-types/src/graphql-websocket-messages.ts index 0a587f450..b0ffa5552 100644 --- a/packages/framework-types/src/graphql-websocket-messages.ts +++ b/packages/framework-types/src/graphql-websocket-messages.ts @@ -61,5 +61,5 @@ export class GraphQLComplete { } export const graphQLWebsocketSubprotocolHeaders = { - 'Sec-WebSocket-Protocol': 'graphql-ws', + 'Sec-WebSocket-Protocol': 'graphql-transport-ws', } diff --git a/upgrade-v2.md b/upgrade-v2.md index d918e8f80..97688e9a8 100644 --- a/upgrade-v2.md +++ b/upgrade-v2.md @@ -5,3 +5,4 @@ Booster v2 introduces the following breaking changes: 1. **Node 18 support**: Booster v2 has been upgraded to work with Node 18. If you're using an older version of Node, you'll need to upgrade it. 2. **Azure runtime upgraded to v4**: The Azure Functions Runtime has been upgraded from v3 to v4. If you're using Booster v1.x.x with Azure, you may need to perform a migration. Check out [Azure's migration guide](https://learn.microsoft.com/en-us/azure/azure-functions/migrate-version-3-version-4?tabs=net6-isolated%2Cazure-cli%2Cwindows&pivots=programming-language-typescript) for more details. 3. **The AWS provider has been deprecated**: Due to significant changes in recent versions of the AWS CDK, specifically the transition from CDKToolkit to a cli tool as noted [here](https://github.com/aws/aws-cdk-rfcs/issues/300), upgrading our current implementation would require a substantial rewrite. Given the open-source nature of our project without direct revenue streams, the ensuing maintenance costs are unfeasible. However, we are open to upgrading the AWS provider or creating an alternative implementation using other technologies like Terraform's CDKTF, with community contributions or sponsorships. If you're interested in supporting us, we welcome you to reach out via the official channels listed on the [Booster's website](https://boosterframework.com). +4. **GraphQL Subscriptions now use the `graphql-transport-ws` subprotocol**: The subprotolcol `graphql-ws`, provided by the package `subscriptions-transport-ws`, has been deprecated in favor of the subprotocol `graphql-transport-ws`, implemented by the package `graphql-ws`. If you were forcing the use of this subprotocol in your client apps, you'll need to update your code to use the new one. If you're using Apollo Client, it will automatically pick the new subprotocol. You can find examples in the Booster documentation. diff --git a/website/docs/06_graphql.md b/website/docs/06_graphql.md index 2f9311fea..326997a35 100644 --- a/website/docs/06_graphql.md +++ b/website/docs/06_graphql.md @@ -251,7 +251,7 @@ In the following examples we use [`wscat`](https://github.com/websockets/wscat) 1. Connect to the web socket: ```sh - wscat -c -s graphql-ws + wscat -c -s graphql-transport-ws ``` :::note