AAE-32999 Removed subscriptions-transport-ws feature flag (#10727)

* AAE-32999 Removed subscriptions-transport-ws feature flag

* AAE-32999 Fixing unit test

* AAE-32999 Fixing unit test

* AAE-32999 Fixing unit test
This commit is contained in:
Ehsan Rezaei 2025-03-18 19:37:58 +01:00 committed by GitHub
parent 838b3e78b7
commit b643054a15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 39 additions and 108 deletions

View File

@ -29,7 +29,6 @@
"allowedNonPeerDependencies": [
"@apollo/client",
"apollo-angular",
"subscriptions-transport-ws",
"@editorjs/editorjs",
"@editorjs/code",
"@editorjs/header",

View File

@ -41,8 +41,7 @@
"@alfresco/adf-content-services": ">=8.0.0",
"@apollo/client": ">=3.7.2",
"@ngx-translate/core": ">=14.0.0",
"apollo-angular": ">=4.0.1",
"subscriptions-transport-ws": ">=0.11.0"
"apollo-angular": ">=4.0.1"
},
"keywords": [
"process-services-cloud",

View File

@ -17,12 +17,11 @@
import { TestBed } from '@angular/core/testing';
import { NotificationCloudService } from './notification-cloud.service';
import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags';
import { WebSocketService } from './web-socket.service';
import { Apollo } from 'apollo-angular';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AuthenticationService } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { of, Subject } from 'rxjs';
describe('NotificationCloudService', () => {
let service: NotificationCloudService;
@ -46,7 +45,6 @@ describe('NotificationCloudService', () => {
imports: [HttpClientTestingModule],
providers: [
WebSocketService,
provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }),
{
provide: Apollo,
useValue: apolloMock
@ -62,6 +60,7 @@ describe('NotificationCloudService', () => {
});
service = TestBed.inject(NotificationCloudService);
wsService = TestBed.inject(WebSocketService);
apolloMock.use.and.returnValue(of({}));
});
it('should call getSubscription with the correct parameters', () => {
@ -72,7 +71,7 @@ describe('NotificationCloudService', () => {
expect(getSubscriptionSpy).toHaveBeenCalledWith({
apolloClientName: 'myAppName',
wsUrl: 'myAppName/notifications',
httpUrl: 'myAppName/notifications/graphql',
httpUrl: 'myAppName/notifications/v2/ws/graphql',
subscriptionOptions: {
query: jasmine.any(Object)
}

View File

@ -28,7 +28,7 @@ export class NotificationCloudService {
return this.webSocketService.getSubscription({
apolloClientName: appName,
wsUrl: `${appName}/notifications`,
httpUrl: `${appName}/notifications/graphql`,
httpUrl: `${appName}/notifications/v2/ws/graphql`,
subscriptionOptions: {
query: gql(gqlQuery)
}

View File

@ -22,14 +22,12 @@ import { WebSocketService } from './web-socket.service';
import { SubscriptionOptions } from '@apollo/client/core';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AuthenticationService, AppConfigService } from '@alfresco/adf-core';
import { FeaturesServiceToken } from '@alfresco/adf-core/feature-flags';
describe('WebSocketService', () => {
let service: WebSocketService;
const onLogoutSubject: Subject<void> = new Subject<void>();
const apolloMock = jasmine.createSpyObj('Apollo', ['use', 'createNamed']);
const isOnSpy = jasmine.createSpy('isOn$');
beforeEach(() => {
TestBed.configureTestingModule({
@ -51,19 +49,11 @@ describe('WebSocketService', () => {
getToken: () => 'testToken',
onLogout: onLogoutSubject.asObservable()
}
},
{
provide: FeaturesServiceToken,
useValue: {
isOn$: isOnSpy
}
}
]
});
service = TestBed.inject(WebSocketService);
TestBed.inject(FeaturesServiceToken);
apolloMock.use.and.returnValues(undefined, { subscribe: () => of({}) });
isOnSpy.and.returnValues(of(true));
});
afterEach(() => {
@ -115,22 +105,4 @@ describe('WebSocketService', () => {
expect(apolloMock.createNamed).toHaveBeenCalled();
expect(headers).toEqual(expectedHeaders);
});
it('should create named client with the right authentication token when FF is off', async () => {
isOnSpy.and.returnValues(of(false));
let headers = {};
const expectedHeaders = { 'X-Authorization': 'Bearer testToken' };
const apolloClientName = 'testClient';
const subscriptionOptions: SubscriptionOptions = { query: gql(`subscription {testQuery}`) };
const wsOptions = { apolloClientName, wsUrl: 'testUrl', subscriptionOptions };
apolloMock.createNamed.and.callFake((_, options) => {
headers = options.headers;
});
await lastValueFrom(service.getSubscription(wsOptions));
expect(apolloMock.use).toHaveBeenCalledTimes(2);
expect(apolloMock.createNamed).toHaveBeenCalled();
expect(headers).toEqual(expectedHeaders);
});
});

View File

@ -16,7 +16,7 @@
*/
import { createClient } from 'graphql-ws';
import { inject, Inject, Injectable, Optional } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { WebSocketLink } from '@apollo/client/link/ws';
import {
@ -37,9 +37,8 @@ import { Kind, OperationTypeNode } from 'graphql';
import { onError } from '@apollo/client/link/error';
import { RetryLink } from '@apollo/client/link/retry';
import { getMainDefinition } from '@apollo/client/utilities';
import { switchMap, take, tap } from 'rxjs/operators';
import { take } from 'rxjs/operators';
import { AppConfigService, AuthenticationService } from '@alfresco/adf-core';
import { FeaturesServiceToken, IFeaturesService } from '@alfresco/adf-core/feature-flags';
interface serviceOptions {
apolloClientName: string;
@ -53,16 +52,11 @@ interface serviceOptions {
})
export class WebSocketService {
private appConfigService = inject(AppConfigService);
private subscriptionProtocol: 'graphql-ws' | 'transport-ws' = 'transport-ws';
private subscriptionProtocol = 'graphql-ws';
private wsLink: GraphQLWsLink | WebSocketLink;
private httpLinkHandler: HttpLinkHandler;
constructor(
private readonly apollo: Apollo,
private readonly httpLink: HttpLink,
private readonly authService: AuthenticationService,
@Optional() @Inject(FeaturesServiceToken) private featuresService: IFeaturesService
) {}
constructor(private readonly apollo: Apollo, private readonly httpLink: HttpLink, private readonly authService: AuthenticationService) {}
public getSubscription<T>(options: serviceOptions): Observable<FetchResult<T>> {
const { apolloClientName, subscriptionOptions } = options;
@ -72,19 +66,10 @@ export class WebSocketService {
}
});
return this.featuresService.isOn$('studio-ws-graphql-subprotocol').pipe(
tap((isOn) => {
if (isOn) {
this.subscriptionProtocol = 'graphql-ws';
}
}),
switchMap(() => {
if (this.apollo.use(apolloClientName) === undefined) {
this.initSubscriptions(options);
}
return this.apollo.use(apolloClientName).subscribe<T>({ errorPolicy: 'all', ...subscriptionOptions });
})
);
if (this.apollo.use(apolloClientName) === undefined) {
this.initSubscriptions(options);
}
return this.apollo.use(apolloClientName).subscribe<T>({ errorPolicy: 'all', ...subscriptionOptions });
}
private get contextRoot() {
@ -106,16 +91,7 @@ export class WebSocketService {
}
private initSubscriptions(options: serviceOptions): void {
switch (this.subscriptionProtocol) {
case 'graphql-ws':
this.createGraphQLWsLink(options);
break;
case 'transport-ws':
this.createTransportWsLink(options);
break;
default:
throw new Error('Unknown subscription protocol');
}
this.createGraphQLWsLink(options);
this.createHttpLinkHandler(options);
@ -175,20 +151,6 @@ export class WebSocketService {
});
}
private createTransportWsLink(options: serviceOptions): void {
this.wsLink = new WebSocketLink({
uri: this.createWsUrl(options.wsUrl) + '/ws/graphql',
options: {
reconnect: true,
lazy: true,
connectionParams: {
kaInterval: 2000,
'X-Authorization': 'Bearer ' + this.authService.getToken()
}
}
});
}
private createGraphQLWsLink(options: serviceOptions): void {
this.wsLink = new GraphQLWsLink(
createClient({

43
package-lock.json generated
View File

@ -20,7 +20,7 @@
"@angular/platform-browser": "17.1.3",
"@angular/platform-browser-dynamic": "17.1.3",
"@angular/router": "17.1.3",
"@apollo/client": "3.11.4",
"@apollo/client": "^3.13.4",
"@cspell/eslint-plugin": "8.16.1",
"@mat-datetimepicker/core": "13.0.2",
"@ngx-translate/core": "^14.0.0",
@ -41,7 +41,6 @@
"pdfjs-dist": "3.3.122",
"raphael": "2.3.0",
"rxjs": "7.8.1",
"subscriptions-transport-ws": "^0.11.0",
"superagent": "^9.0.1",
"ts-morph": "^20.0.0",
"tslib": "2.8.1",
@ -1416,9 +1415,9 @@
}
},
"node_modules/@apollo/client": {
"version": "3.11.4",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.11.4.tgz",
"integrity": "sha512-bmgYKkULpym8wt8aXlAZ1heaYo0skLJ5ru0qJ+JCRoo03Pe+yIDbBCnqlDw6Mjj76hFkDw3HwFMgZC2Hxp30Mg==",
"version": "3.13.4",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.13.4.tgz",
"integrity": "sha512-Ot3RaN2M/rhIKDqXBdOVlN0dQbHydUrYJ9lTxkvd6x7W1pAjwduUccfoz2gsO4U9by7oWtRj/ySF0MFNUp+9Aw==",
"license": "MIT",
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
@ -1430,7 +1429,6 @@
"optimism": "^0.18.0",
"prop-types": "^15.7.2",
"rehackt": "^0.1.0",
"response-iterator": "^0.2.6",
"symbol-observable": "^4.0.0",
"ts-invariant": "^0.10.3",
"tslib": "^2.3.0",
@ -1438,9 +1436,9 @@
},
"peerDependencies": {
"graphql": "^15.0.0 || ^16.0.0",
"graphql-ws": "^5.5.5",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0",
"graphql-ws": "^5.5.5 || ^6.0.3",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc",
"subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
},
"peerDependenciesMeta": {
@ -20273,7 +20271,9 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
@ -27414,7 +27414,9 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jackspeak": {
"version": "3.4.3",
@ -35599,15 +35601,6 @@
"node": ">=10"
}
},
"node_modules/response-iterator": {
"version": "0.2.20",
"resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.20.tgz",
"integrity": "sha512-RfNi9saiJ9VKznrRZEGZtlfeiQI7NWMUlXvmkvO60xaHfW1y+36EOibZkV59LuKNak8VIqL6IyxYxhMOGTurIQ==",
"license": "MIT",
"engines": {
"node": ">=0.8"
}
},
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@ -37865,6 +37858,8 @@
"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",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"backo2": "^1.0.2",
"eventemitter3": "^3.1.0",
@ -37880,13 +37875,17 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"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==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -37896,6 +37895,8 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8.3.0"
},

View File

@ -40,7 +40,7 @@
"@angular/platform-browser": "17.1.3",
"@angular/platform-browser-dynamic": "17.1.3",
"@angular/router": "17.1.3",
"@apollo/client": "3.11.4",
"@apollo/client": "^3.13.4",
"@cspell/eslint-plugin": "8.16.1",
"@mat-datetimepicker/core": "13.0.2",
"@ngx-translate/core": "^14.0.0",
@ -61,7 +61,6 @@
"pdfjs-dist": "3.3.122",
"raphael": "2.3.0",
"rxjs": "7.8.1",
"subscriptions-transport-ws": "^0.11.0",
"superagent": "^9.0.1",
"ts-morph": "^20.0.0",
"tslib": "2.8.1",
@ -95,13 +94,12 @@
"@nx/workspace": "17.3.1",
"@paperist/types-remark": "0.1.3",
"@playwright/test": "1.46.1",
"@valano/change-font-size": "^1.0.0",
"@schematics/angular": "17.1.4",
"@storybook/addon-essentials": "8.4.7",
"@storybook/addon-interactions": "8.4.7",
"@storybook/angular": "^8.4.6",
"@storybook/core-server": "8.4.7",
"@storybook/manager-api": "^8.4.5",
"@storybook/addon-interactions": "8.4.7",
"@storybook/theming": "^8.2.9",
"@types/ejs": "^3.1.5",
"@types/event-emitter": "^0.3.3",
@ -119,6 +117,7 @@
"@typescript-eslint/parser": "6.21.0",
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/utils": "^8.8.1",
"@valano/change-font-size": "^1.0.0",
"ajv": "^8.12.0",
"commander": "12.0.0",
"css-loader": "^7.1.2",