From a5320b0db0942aba3dbe41b9a853714f0278d545 Mon Sep 17 00:00:00 2001 From: DmitryAnansky Date: Fri, 11 Oct 2024 19:15:23 +0300 Subject: [PATCH] chore: replace node-fetch with native fetch --- package-lock.json | 75 ++++--------------- package.json | 2 +- packages/cli/package.json | 3 +- .../__tests__/commands/push-region.test.ts | 16 ++-- .../cli/src/__tests__/commands/push.test.ts | 16 ++-- .../src/__tests__/fetch-with-timeout.test.ts | 14 ++-- .../src/cms/api/__tests__/api.client.test.ts | 51 +++++++------ packages/cli/src/cms/api/api-client.ts | 4 +- packages/cli/src/commands/push.ts | 6 +- packages/cli/src/utils/fetch-with-timeout.ts | 14 ++-- packages/core/package.json | 8 +- packages/core/src/env.d.ts | 2 + .../redocly/__tests__/redocly-client.test.ts | 8 +- packages/core/src/redocly/registry-api.ts | 2 - packages/core/src/utils.ts | 1 - 15 files changed, 94 insertions(+), 128 deletions(-) create mode 100644 packages/core/src/env.d.ts diff --git a/package-lock.json b/package-lock.json index cf770b7f2..7e221e05e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "webpack-cli": "^4.10.0" }, "engines": { - "node": ">=15.0.0", + "node": ">=18.17.0", "npm": ">=7.0.0" } }, @@ -3790,16 +3790,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", @@ -6839,20 +6829,6 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -13752,7 +13728,6 @@ "glob": "^7.1.6", "handlebars": "^4.7.6", "mobx": "^6.0.4", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "react": "^17.0.0 || ^18.2.0", "react-dom": "^17.0.0 || ^18.2.0", @@ -13777,7 +13752,7 @@ "typescript": "5.5.3" }, "engines": { - "node": ">=14.19.0", + "node": ">=18.17.0", "npm": ">=7.0.0" } }, @@ -13801,13 +13776,13 @@ "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.12.1", + "abort-controller": "^3.0.0", "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "lodash.isequal": "^4.5.0", "minimatch": "^5.0.1", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" }, @@ -13817,13 +13792,12 @@ "@types/lodash.isequal": "^4.5.5", "@types/minimatch": "^3.0.5", "@types/node": "^20.11.5", - "@types/node-fetch": "^2.5.7", "@types/pluralize": "^0.0.29", "json-schema-to-ts": "^3.1.0", "typescript": "5.5.3" }, "engines": { - "node": ">=14.19.0", + "node": ">=18.17.0", "npm": ">=7.0.0" } }, @@ -13839,9 +13813,9 @@ } }, "packages/core/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -16477,7 +16451,6 @@ "glob": "^7.1.6", "handlebars": "^4.7.6", "mobx": "^6.0.4", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "react": "^17.0.0 || ^18.2.0", "react-dom": "^17.0.0 || ^18.2.0", @@ -16516,16 +16489,15 @@ "@types/lodash.isequal": "^4.5.5", "@types/minimatch": "^3.0.5", "@types/node": "^20.11.5", - "@types/node-fetch": "^2.5.7", "@types/pluralize": "^0.0.29", + "abort-controller": "^3.0.0", "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "json-schema-to-ts": "^3.1.0", "lodash.isequal": "^4.5.0", "minimatch": "^5.0.1", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "typescript": "5.5.3", "yaml-ast-parser": "0.0.43" @@ -16540,9 +16512,9 @@ } }, "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "requires": { "agent-base": "^7.0.2", "debug": "4" @@ -16806,16 +16778,6 @@ "undici-types": "~5.26.4" } }, - "@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, "@types/normalize-package-data": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", @@ -19115,17 +19077,6 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", diff --git a/package.json b/package.json index 609d1f227..8a55ffd8c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "private": true, "engines": { - "node": ">=15.0.0", + "node": ">=18.17.0", "npm": ">=7.0.0" }, "engineStrict": true, diff --git a/packages/cli/package.json b/packages/cli/package.json index 89bff9bd1..d34b3cadb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -8,7 +8,7 @@ "redocly": "bin/cli.js" }, "engines": { - "node": ">=14.19.0", + "node": ">=18.17.0", "npm": ">=7.0.0" }, "engineStrict": true, @@ -46,7 +46,6 @@ "glob": "^7.1.6", "handlebars": "^4.7.6", "mobx": "^6.0.4", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "react": "^17.0.0 || ^18.2.0", "react-dom": "^17.0.0 || ^18.2.0", diff --git a/packages/cli/src/__tests__/commands/push-region.test.ts b/packages/cli/src/__tests__/commands/push-region.test.ts index a0e4bb188..391512924 100644 --- a/packages/cli/src/__tests__/commands/push-region.test.ts +++ b/packages/cli/src/__tests__/commands/push-region.test.ts @@ -4,12 +4,6 @@ import { promptClientToken } from '../../commands/login'; import { ConfigFixture } from '../fixtures/config'; jest.mock('fs'); -jest.mock('node-fetch', () => ({ - default: jest.fn(() => ({ - ok: true, - json: jest.fn().mockResolvedValue({}), - })), -})); jest.mock('@redocly/openapi-core'); jest.mock('../../commands/login'); jest.mock('../../utils/miscellaneous'); @@ -22,8 +16,18 @@ describe('push-with-region', () => { const redoclyClient = require('@redocly/openapi-core').__redoclyClient; redoclyClient.isAuthorizedWithRedoclyByRegion = jest.fn().mockResolvedValue(false); + afterAll(() => { + jest.restoreAllMocks(); // Restore original fetch after tests + }); + beforeAll(() => { jest.spyOn(process.stdout, 'write').mockImplementation(() => true); + global.fetch = jest.fn(() => + Promise.resolve({ + ok: true, + json: jest.fn().mockResolvedValue({}), // Mocked JSON response + } as unknown as Response) + ); }); it('should call login with default domain when region is US', async () => { diff --git a/packages/cli/src/__tests__/commands/push.test.ts b/packages/cli/src/__tests__/commands/push.test.ts index 2fe8c36d6..ede7a3ac1 100644 --- a/packages/cli/src/__tests__/commands/push.test.ts +++ b/packages/cli/src/__tests__/commands/push.test.ts @@ -6,12 +6,6 @@ import { ConfigFixture } from '../fixtures/config'; import { yellow } from 'colorette'; jest.mock('fs'); -jest.mock('node-fetch', () => ({ - default: jest.fn(() => ({ - ok: true, - json: jest.fn().mockResolvedValue({}), - })), -})); jest.mock('@redocly/openapi-core'); jest.mock('../../utils/miscellaneous'); @@ -22,6 +16,16 @@ describe('push', () => { beforeEach(() => { jest.spyOn(process.stdout, 'write').mockImplementation(() => true); + global.fetch = jest.fn(() => + Promise.resolve({ + ok: true, + json: jest.fn().mockResolvedValue({}), // Mocked JSON response + } as unknown as Response) + ); + }); + + afterAll(() => { + jest.restoreAllMocks(); // Restore original fetch after tests }); it('pushes definition', async () => { diff --git a/packages/cli/src/__tests__/fetch-with-timeout.test.ts b/packages/cli/src/__tests__/fetch-with-timeout.test.ts index 20c5e8446..a0c2b0df9 100644 --- a/packages/cli/src/__tests__/fetch-with-timeout.test.ts +++ b/packages/cli/src/__tests__/fetch-with-timeout.test.ts @@ -1,10 +1,8 @@ import AbortController from 'abort-controller'; import fetchWithTimeout from '../utils/fetch-with-timeout'; -import nodeFetch from 'node-fetch'; import { getProxyAgent } from '@redocly/openapi-core'; import { HttpsProxyAgent } from 'https-proxy-agent'; -jest.mock('node-fetch'); jest.mock('@redocly/openapi-core'); describe('fetchWithTimeout', () => { @@ -16,6 +14,12 @@ describe('fetchWithTimeout', () => { beforeEach(() => { (getProxyAgent as jest.Mock).mockReturnValueOnce(undefined); + global.fetch = jest.fn(() => + Promise.resolve({ + ok: true, + json: jest.fn().mockResolvedValue({}), // Mocked JSON response + } as unknown as Response) + ); }); afterEach(() => { @@ -26,7 +30,7 @@ describe('fetchWithTimeout', () => { await fetchWithTimeout('url', { timeout: 1000 }); expect(global.setTimeout).toHaveBeenCalledTimes(1); - expect(nodeFetch).toHaveBeenCalledWith('url', { + expect(fetch).toHaveBeenCalledWith('url', { signal: new AbortController().signal, agent: undefined, }); @@ -40,14 +44,14 @@ describe('fetchWithTimeout', () => { await fetchWithTimeout('url'); - expect(nodeFetch).toHaveBeenCalledWith('url', { agent: proxyAgent }); + expect(fetch).toHaveBeenCalledWith('url', { agent: proxyAgent }); }); it('should call node-fetch without signal when timeout is not passed', async () => { await fetchWithTimeout('url'); expect(global.setTimeout).not.toHaveBeenCalled(); - expect(nodeFetch).toHaveBeenCalledWith('url', { agent: undefined }); + expect(fetch).toHaveBeenCalledWith('url', { agent: undefined }); expect(global.clearTimeout).not.toHaveBeenCalled(); }); }); diff --git a/packages/cli/src/cms/api/__tests__/api.client.test.ts b/packages/cli/src/cms/api/__tests__/api.client.test.ts index 77d4e5a3d..f2839965a 100644 --- a/packages/cli/src/cms/api/__tests__/api.client.test.ts +++ b/packages/cli/src/cms/api/__tests__/api.client.test.ts @@ -1,17 +1,8 @@ -import fetch, { Response } from 'node-fetch'; import * as FormData from 'form-data'; import { red, yellow } from 'colorette'; import { ReuniteApi, PushPayload, ReuniteApiError } from '../api-client'; -jest.mock('node-fetch', () => ({ - default: jest.fn(), -})); - -function mockFetchResponse(response: any) { - (fetch as jest.MockedFunction).mockResolvedValue(response as unknown as Response); -} - describe('ApiClient', () => { const testToken = 'test-token'; const testDomain = 'test-domain.com'; @@ -21,6 +12,22 @@ describe('ApiClient', () => { const command = 'push'; const expectedUserAgent = `redocly-cli/${version} ${command}`; + beforeAll(() => { + // Initialize fetch as a mock function + global.fetch = jest.fn(); + }); + + afterAll(() => { + jest.restoreAllMocks(); // Restore original fetch after tests + }); + + // Function to mock fetch responses + function mockFetchResponse(response: Response | Promise) { + (global.fetch as jest.MockedFunction).mockImplementation(() => + Promise.resolve(response) + ); + } + describe('getDefaultBranch()', () => { let apiClient: ReuniteApi; @@ -34,7 +41,7 @@ describe('ApiClient', () => { json: jest.fn().mockResolvedValue({ branchName: 'test-branch', }), - }); + } as unknown as Response); const result = await apiClient.remotes.getDefaultBranch(testOrg, testProject); @@ -64,7 +71,7 @@ describe('ApiClient', () => { detail: 'Not Found', object: 'problem', }), - }); + } as unknown as Response); await expect(apiClient.remotes.getDefaultBranch(testOrg, testProject)).rejects.toThrow( new ReuniteApiError('Failed to fetch default branch. Project source not found.', 404) @@ -78,7 +85,7 @@ describe('ApiClient', () => { json: jest.fn().mockResolvedValue({ unknownField: 'unknown-error', }), - }); + } as unknown as Response); await expect(apiClient.remotes.getDefaultBranch(testOrg, testProject)).rejects.toThrow( new ReuniteApiError('Failed to fetch default branch. Not found.', 404) @@ -111,7 +118,7 @@ describe('ApiClient', () => { mockFetchResponse({ ok: true, json: jest.fn().mockResolvedValue(responseMock), - }); + } as unknown as Response); const result = await apiClient.remotes.upsert(testOrg, testProject, remotePayload); @@ -148,7 +155,7 @@ describe('ApiClient', () => { detail: 'Forbidden', object: 'problem', }), - }); + } as unknown as Response); await expect(apiClient.remotes.upsert(testOrg, testProject, remotePayload)).rejects.toThrow( new ReuniteApiError( @@ -166,7 +173,7 @@ describe('ApiClient', () => { json: jest.fn().mockResolvedValue({ unknownField: 'unknown-error', }), - }); + } as unknown as Response); await expect(apiClient.remotes.upsert(testOrg, testProject, remotePayload)).rejects.toThrow( new ReuniteApiError('Failed to upsert remote. Not found.', 404) @@ -264,7 +271,7 @@ describe('ApiClient', () => { detail: 'Forbidden', object: 'problem', }), - }); + } as unknown as Response); await expect( apiClient.remotes.push(testOrg, testProject, pushPayload, filesMock) @@ -279,7 +286,7 @@ describe('ApiClient', () => { json: jest.fn().mockResolvedValue({ unknownField: 'unknown-error', }), - }); + } as unknown as Response); await expect( apiClient.remotes.push(testOrg, testProject, pushPayload, filesMock) @@ -366,7 +373,7 @@ describe('ApiClient', () => { headers: new Headers({ Sunset: sunsetDate.toISOString(), }), - }); + } as unknown as Response); await requestFn(); apiClient.reportSunsetWarnings(); @@ -391,7 +398,7 @@ describe('ApiClient', () => { headers: new Headers({ Sunset: sunsetDate.toISOString(), }), - }); + } as unknown as Response); await requestFn(); apiClient.reportSunsetWarnings(); @@ -413,7 +420,7 @@ describe('ApiClient', () => { headers: new Headers({ Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(), }), - }); + } as unknown as Response); await upsertRemoteMock.requestFn(); @@ -423,7 +430,7 @@ describe('ApiClient', () => { headers: new Headers({ Sunset: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), }), - }); + } as unknown as Response); await getDefaultBranchMock.requestFn(); @@ -433,7 +440,7 @@ describe('ApiClient', () => { headers: new Headers({ Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(), }), - }); + } as unknown as Response); await pushMock.requestFn(); diff --git a/packages/cli/src/cms/api/api-client.ts b/packages/cli/src/cms/api/api-client.ts index 3cd0fa567..6169a1d17 100644 --- a/packages/cli/src/cms/api/api-client.ts +++ b/packages/cli/src/cms/api/api-client.ts @@ -5,7 +5,6 @@ import fetchWithTimeout, { DEFAULT_FETCH_TIMEOUT, } from '../../utils/fetch-with-timeout'; -import type { Response } from 'node-fetch'; import type { ReadStream } from 'fs'; import type { ListRemotesResponse, @@ -196,6 +195,7 @@ class RemotesApi { } payload.isMainBranch && formData.append('isMainBranch', 'true'); + try { const response = await this.client.request( `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`, @@ -204,7 +204,7 @@ class RemotesApi { headers: { Authorization: `Bearer ${this.apiKey}`, }, - body: formData, + body: formData as any, } ); diff --git a/packages/cli/src/commands/push.ts b/packages/cli/src/commands/push.ts index 3a6255bc8..f11e5bae4 100644 --- a/packages/cli/src/commands/push.ts +++ b/packages/cli/src/commands/push.ts @@ -1,6 +1,5 @@ import * as fs from 'fs'; import * as path from 'path'; -import fetch from 'node-fetch'; import { performance } from 'perf_hooks'; import { yellow, green, blue, red } from 'colorette'; import { createHash } from 'crypto'; @@ -14,6 +13,7 @@ import { getProxyAgent, } from '@redocly/openapi-core'; import { pluralize } from '@redocly/openapi-core/lib/utils'; +import { isBrowser } from '@redocly/openapi-core/lib/env'; import { exitWithError, printExecutionTime, @@ -450,7 +450,7 @@ function uploadFileToS3(url: string, filePathOrBuffer: string | Buffer) { headers: { 'Content-Length': fileSizeInBytes.toString(), }, - body: readStream, - agent: getProxyAgent(), + body: readStream as Buffer, + ...(isBrowser ? {} : { agent: getProxyAgent() }), }); } diff --git a/packages/cli/src/utils/fetch-with-timeout.ts b/packages/cli/src/utils/fetch-with-timeout.ts index 5bfcba4d4..8f69417c4 100644 --- a/packages/cli/src/utils/fetch-with-timeout.ts +++ b/packages/cli/src/utils/fetch-with-timeout.ts @@ -1,6 +1,6 @@ -import nodeFetch, { type RequestInit } from 'node-fetch'; import AbortController from 'abort-controller'; import { getProxyAgent } from '@redocly/openapi-core'; +import { isBrowser } from '@redocly/openapi-core/lib/env'; export const DEFAULT_FETCH_TIMEOUT = 3000; @@ -10,21 +10,21 @@ export type FetchWithTimeoutOptions = RequestInit & { export default async (url: string, { timeout, ...options }: FetchWithTimeoutOptions = {}) => { if (!timeout) { - return nodeFetch(url, { + return fetch(url, { ...options, - agent: getProxyAgent(), + ...(isBrowser ? {} : { agent: getProxyAgent() }), // Conditionally add agent only in Node.js }); } - const controller = new AbortController(); + const controller = isBrowser ? new window.AbortController() : new AbortController(); const timeoutId = setTimeout(() => { controller.abort(); }, timeout); - const res = await nodeFetch(url, { - signal: controller.signal, + const res = await fetch(url, { + signal: controller.signal as AbortSignal, ...options, - agent: getProxyAgent(), + ...(isBrowser ? {} : { agent: getProxyAgent() }), }); clearTimeout(timeoutId); diff --git a/packages/core/package.json b/packages/core/package.json index 935a53836..49d909694 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -4,7 +4,7 @@ "description": "", "main": "lib/index.js", "engines": { - "node": ">=14.19.0", + "node": ">=18.17.0", "npm": ">=7.0.0" }, "engineStrict": true, @@ -17,7 +17,6 @@ "fs": false, "path": "path-browserify", "os": false, - "node-fetch": false, "colorette": false, "https-proxy-agent": false }, @@ -37,13 +36,13 @@ "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.12.1", + "abort-controller": "^3.0.0", "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "lodash.isequal": "^4.5.0", "minimatch": "^5.0.1", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" }, @@ -53,7 +52,6 @@ "@types/lodash.isequal": "^4.5.5", "@types/minimatch": "^3.0.5", "@types/node": "^20.11.5", - "@types/node-fetch": "^2.5.7", "@types/pluralize": "^0.0.29", "json-schema-to-ts": "^3.1.0", "typescript": "5.5.3" diff --git a/packages/core/src/env.d.ts b/packages/core/src/env.d.ts new file mode 100644 index 000000000..802553eb7 --- /dev/null +++ b/packages/core/src/env.d.ts @@ -0,0 +1,2 @@ +export declare const isBrowser: boolean; +export declare const env: NodeJS.ProcessEnv; diff --git a/packages/core/src/redocly/__tests__/redocly-client.test.ts b/packages/core/src/redocly/__tests__/redocly-client.test.ts index 0e19752d6..06973581c 100644 --- a/packages/core/src/redocly/__tests__/redocly-client.test.ts +++ b/packages/core/src/redocly/__tests__/redocly-client.test.ts @@ -1,12 +1,12 @@ import { setRedoclyDomain } from '../domains'; import { RedoclyClient } from '../index'; -jest.mock('node-fetch', () => ({ - default: jest.fn(() => ({ +global.fetch = jest.fn(() => + Promise.resolve({ ok: true, json: jest.fn().mockResolvedValue({}), - })), -})); + } as any) +); describe('RedoclyClient', () => { const REDOCLY_DOMAIN_US = 'redocly.com'; diff --git a/packages/core/src/redocly/registry-api.ts b/packages/core/src/redocly/registry-api.ts index ff6abafde..31132df4d 100644 --- a/packages/core/src/redocly/registry-api.ts +++ b/packages/core/src/redocly/registry-api.ts @@ -1,8 +1,6 @@ -import fetch from 'node-fetch'; import { getProxyAgent, isNotEmptyObject } from '../utils'; import { getRedoclyDomain } from './domains'; -import type { RequestInit, HeadersInit } from 'node-fetch'; import type { NotFoundProblemResponse, PrepareFileuploadOKResponse, diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 994319dde..a74ef2627 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,7 +1,6 @@ import * as fs from 'fs'; import { extname } from 'path'; import * as minimatch from 'minimatch'; -import fetch from 'node-fetch'; import { parseYaml } from './js-yaml'; import { env } from './env'; import { logger, colorize } from './logger';