diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index e4ba300d27..b8f69cebe1 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -70,6 +70,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", + "@microsoft/fetch-event-source": "^2.0.1", "@react-hookz/web": "^24.0.0", "@rjsf/core": "5.18.2", "@rjsf/material-ui": "5.18.2", @@ -78,7 +79,6 @@ "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", - "event-source-polyfill": "^1.0.31", "git-url-parse": "^14.0.0", "humanize-duration": "^3.25.1", "json-schema": "^0.4.0", @@ -103,7 +103,6 @@ "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^15.0.0", "@testing-library/user-event": "^14.0.0", - "@types/event-source-polyfill": "^1.0.0", "@types/humanize-duration": "^3.18.1", "@types/json-schema": "^7.0.9", "msw": "^1.0.0" diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index b9b1881066..cf482e52f7 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -20,14 +20,13 @@ import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ScaffolderClient } from './api'; -import { EventSourcePolyfill } from 'event-source-polyfill'; +import { fetchEventSource } from '@microsoft/fetch-event-source'; -const MockedEventSource = EventSourcePolyfill as jest.MockedClass< - typeof EventSourcePolyfill +jest.mock('@microsoft/fetch-event-source'); +const mockFetchEventSource = fetchEventSource as jest.MockedFunction< + typeof fetchEventSource >; -jest.mock('event-source-polyfill'); - const server = setupServer(); describe('api', () => { @@ -87,26 +86,23 @@ describe('api', () => { describe('streamEvents', () => { describe('eventsource', () => { it('should work', async () => { - MockedEventSource.prototype.addEventListener.mockImplementation( - (type, fn) => { - if (typeof fn !== 'function') { - return; - } - - if (type === 'log') { - fn({ - data: '{"id":1,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}}', - } as any); - } else if (type === 'completion') { - fn({ - data: '{"id":2,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}}', - } as any); - } - }, - ); - - const token = 'fake-token'; - identityApi.getCredentials.mockResolvedValue({ token: token }); + mockFetchEventSource.mockImplementation(async (_url, options) => { + const { onopen, onmessage } = options; + await Promise.resolve(); + await onopen?.({ ok: true } as Response); + await Promise.resolve(); + onmessage?.({ + id: '', + event: 'log', + data: '{"id":1,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}}', + }); + await Promise.resolve(); + onmessage?.({ + id: '', + event: 'completion', + data: '{"id":2,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}}', + }); + }); const next = jest.fn(); @@ -116,14 +112,14 @@ describe('api', () => { .subscribe({ next, complete }); }); - expect(MockedEventSource).toHaveBeenCalledWith( + expect(mockFetchEventSource).toHaveBeenCalledWith( 'http://backstage/api/v2/tasks/a-random-task-id/eventstream', { - withCredentials: true, - headers: { Authorization: `Bearer ${token}` }, + fetch: fetchApi.fetch, + onmessage: expect.any(Function), + onerror: expect.any(Function), }, ); - expect(MockedEventSource.prototype.close).toHaveBeenCalled(); expect(next).toHaveBeenCalledTimes(2); expect(next).toHaveBeenCalledWith({ diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index fe0d7c11d0..8dc11ef296 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -41,7 +41,7 @@ import { } from '@backstage/plugin-scaffolder-react'; import queryString from 'qs'; -import { EventSourcePolyfill } from 'event-source-polyfill'; +import { fetchEventSource } from '@microsoft/fetch-event-source'; /** * An API to interact with the scaffolder backend. @@ -226,11 +226,8 @@ export class ScaffolderClient implements ScaffolderApi { params.set('after', String(Number(after))); } - Promise.all([ - this.discoveryApi.getBaseUrl('scaffolder'), - this.identityApi?.getCredentials(), - ]).then( - ([baseUrl, credentials]) => { + this.discoveryApi.getBaseUrl('scaffolder').then( + baseUrl => { const url = `${baseUrl}/v2/tasks/${encodeURIComponent( taskId, )}/eventstream`; @@ -245,22 +242,22 @@ export class ScaffolderClient implements ScaffolderApi { } }; - const eventSource = new EventSourcePolyfill(url, { - withCredentials: true, - headers: credentials?.token - ? { Authorization: `Bearer ${credentials.token}` } - : {}, - }); - eventSource.addEventListener('log', processEvent); - eventSource.addEventListener('recovered', processEvent); - eventSource.addEventListener('cancelled', processEvent); - eventSource.addEventListener('completion', (event: any) => { - processEvent(event); - eventSource.close(); - subscriber.complete(); - }); - eventSource.addEventListener('error', event => { - subscriber.error(event); + fetchEventSource(url, { + fetch: this.fetchApi.fetch, + onmessage(e: any) { + if (e.event === 'log') { + processEvent(e); + return; + } else if (e.event === 'completion') { + processEvent(e); + subscriber.complete(); + return; + } + processEvent(e); + }, + onerror(err) { + subscriber.error(err); + }, }); }, error => { diff --git a/plugins/scaffolder/src/setupTests.ts b/plugins/scaffolder/src/setupTests.ts index 8608e5b98e..7b25d3706a 100644 --- a/plugins/scaffolder/src/setupTests.ts +++ b/plugins/scaffolder/src/setupTests.ts @@ -16,9 +16,6 @@ import '@testing-library/jest-dom'; -const { EventSourcePolyfill } = jest.requireMock('event-source-polyfill'); -global.EventSource = EventSourcePolyfill; - // Patch jsdom to add feature used by CodeMirror document.createRange = () => { const range = new Range(); diff --git a/plugins/techdocs/api-report.md b/plugins/techdocs/api-report.md index ff43f4309b..582e941507 100644 --- a/plugins/techdocs/api-report.md +++ b/plugins/techdocs/api-report.md @@ -14,7 +14,6 @@ import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react'; import { FetchApi } from '@backstage/core-plugin-api'; -import { IdentityApi } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; @@ -465,7 +464,6 @@ export class TechDocsStorageClient implements TechDocsStorageApi_2 { constructor(options: { configApi: Config; discoveryApi: DiscoveryApi; - identityApi: IdentityApi; fetchApi: FetchApi; }); // (undocumented) @@ -485,8 +483,6 @@ export class TechDocsStorageClient implements TechDocsStorageApi_2 { getEntityDocs(entityId: CompoundEntityRef, path: string): Promise; // (undocumented) getStorageUrl(): Promise; - // (undocumented) - identityApi: IdentityApi; syncEntityDocs( entityId: CompoundEntityRef, logHandler?: (line: string) => void, diff --git a/yarn.lock b/yarn.lock index 052268febb..3ac0d88613 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6958,6 +6958,7 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 + "@microsoft/fetch-event-source": ^2.0.1 "@react-hookz/web": ^24.0.0 "@rjsf/core": 5.18.2 "@rjsf/material-ui": 5.18.2 @@ -6967,13 +6968,11 @@ __metadata: "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^15.0.0 "@testing-library/user-event": ^14.0.0 - "@types/event-source-polyfill": ^1.0.0 "@types/humanize-duration": ^3.18.1 "@types/json-schema": ^7.0.9 "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 "@uiw/react-codemirror": ^4.9.3 classnames: ^2.2.6 - event-source-polyfill: ^1.0.31 git-url-parse: ^14.0.0 humanize-duration: ^3.25.1 json-schema: ^0.4.0 @@ -17134,13 +17133,6 @@ __metadata: languageName: node linkType: hard -"@types/event-source-polyfill@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/event-source-polyfill@npm:1.0.5" - checksum: f506b68710162f2ade1bccbc5691b8c67e5a703e565df2bc0b7b5be2637ba838ef81ec6c10b03248fe4d054386d95a6e827c7aace6e924986c2b9985f77b55de - languageName: node - linkType: hard - "@types/expect@npm:^1.20.4": version: 1.20.4 resolution: "@types/expect@npm:1.20.4" @@ -25498,13 +25490,6 @@ __metadata: languageName: node linkType: hard -"event-source-polyfill@npm:^1.0.31": - version: 1.0.31 - resolution: "event-source-polyfill@npm:1.0.31" - checksum: 973f226404e2a1b14ed7ef15c718b89e213b41d7cfeeb1c10937fd09229f13904f3d7c3075ab28ccf858c213007559908eecdd577577330352f53a351383dd75 - languageName: node - linkType: hard - "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1"