diff --git a/package.json b/package.json index a3448bab7..13d1b08c4 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,6 @@ "@types/lodash.memoize": "^4.1.3", "@types/micromatch": "^3.1.0", "@types/node": "18.19.18", - "@types/node-fetch": "^2.5.12", "@types/parse-github-url": "^1.0.3", "@types/prettier": "^1.16.1", "@types/readline-sync": "^1.4.3", @@ -132,7 +131,7 @@ "jest-json-reporter": "^1.2.2", "lint-staged": "^12.3.7", "madge": "^6.0.1", - "nock": "^13.2.0", + "nock": "^14.0.15", "pkg": "^5.8.1", "prettier": "^2.5.1", "release-it": "^18.1.2", @@ -152,8 +151,6 @@ "core-js": "^3.8.2", "debug": "^4.1.1", "fast-json-patch": "^3.0.0-1", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.2", "hyperlinker": "^1.0.0", "ini": "^5.0.0", "json5": "^2.2.3", @@ -166,7 +163,6 @@ "memfs-or-file-map-to-github-branch": "^1.3.0", "micromatch": "^4.0.4", "node-cleanup": "^2.1.2", - "node-fetch": "^2.6.7", "override-require": "^1.1.1", "parse-diff": "^0.7.0", "parse-github-url": "^1.0.2", @@ -176,7 +172,8 @@ "readline-sync": "^1.4.9", "regenerator-runtime": "^0.13.9", "require-from-string": "^2.0.2", - "supports-hyperlinks": "^4.3.0" + "supports-hyperlinks": "^4.3.0", + "undici": "6.21.1" }, "resolutions": { "before-after-hook": "2.2.0", diff --git a/source/api/_tests/fetch.test.ts b/source/api/_tests/fetch.test.ts index 5a6fa8294..7cd7bace5 100644 --- a/source/api/_tests/fetch.test.ts +++ b/source/api/_tests/fetch.test.ts @@ -1,8 +1,6 @@ import * as http from "http" -import * as node_fetch from "node-fetch" -import type { HttpProxyAgent } from "http-proxy-agent" -import type { HttpsProxyAgent } from "https-proxy-agent" +import { ProxyAgent } from "undici" import { api } from "../fetch" interface ResponseMock { @@ -42,37 +40,9 @@ class TestServer { } } -class TestProxy { - isRunning = false - private port = 30002 - private hostname = "localhost" - private router = (_req: any, res: any) => { - res.statusCode = 200 - res.end(null) - } - private server = http.createServer(this.router) - - start = async (): Promise => { - return new Promise((resolve, reject) => { - this.isRunning = true - this.server.on("error", (e) => { - reject(e) - }) - this.server.listen(this.port, this.hostname, undefined, () => resolve()) - }) - } - stop = async (): Promise => { - return new Promise((resolve, reject) => { - this.isRunning = false - this.server.close((err: any) => (err ? reject(err) : resolve())) - }) - } -} - describe("fetch", () => { let url: string let server = new TestServer() - let proxy = new TestProxy() beforeEach(() => { url = "http://localhost:30001/" @@ -80,10 +50,6 @@ describe("fetch", () => { afterEach(async () => { await server.stop() - - if (proxy.isRunning) { - await proxy.stop() - } }) it("handles json success", async () => { @@ -125,51 +91,51 @@ describe("fetch", () => { expect(await response.text()).toBe(body) }) - it("sets proxy agent when HTTPS_PROXY env variable is defined", async () => { + it("sets proxy dispatcher when HTTPS_PROXY env variable is defined", async () => { const proxyUrl = "http://localhost:30002/" + const abortController = new AbortController() + abortController.abort() - await proxy.start() await server.start({}) - let options: node_fetch.RequestInit = { agent: undefined } - await api(url, options, true, { HTTPS_PROXY: proxyUrl }) - let agent = options.agent as HttpsProxyAgent - expect(agent["proxy"].href).toBe(proxyUrl) + let options = { method: "GET", dispatcher: undefined, signal: abortController.signal } + await api(url, options, true, { HTTPS_PROXY: proxyUrl }).catch(() => undefined) + expect(options.dispatcher).toBeInstanceOf(ProxyAgent) }) - it("sets proxy agent when https_proxy env variable is defined", async () => { + it("sets proxy dispatcher when https_proxy env variable is defined", async () => { const proxyUrl = "http://localhost:30002/" + const abortController = new AbortController() + abortController.abort() - await proxy.start() await server.start({}) - let options: node_fetch.RequestInit = { agent: undefined } - await api(url, options, true, { https_proxy: proxyUrl }) - let agent = options.agent as HttpsProxyAgent - expect(agent["proxy"].href).toBe(proxyUrl) + let options = { method: "GET", dispatcher: undefined, signal: abortController.signal } + await api(url, options, true, { https_proxy: proxyUrl }).catch(() => undefined) + expect(options.dispatcher).toBeInstanceOf(ProxyAgent) }) - it("sets proxy agent when HTTP_PROXY env variable is defined", async () => { + it("sets proxy dispatcher when HTTP_PROXY env variable is defined", async () => { const proxyUrl = "http://localhost:30002/" + const abortController = new AbortController() + abortController.abort() - await proxy.start() await server.start({}) - let options: node_fetch.RequestInit = { agent: undefined } - await api(url, options, true, { HTTP_PROXY: proxyUrl }) - let agent = options.agent as HttpProxyAgent - expect(agent["proxy"].href).toBe(proxyUrl) + let options = { method: "GET", dispatcher: undefined, signal: abortController.signal } + await api(url, options, true, { HTTP_PROXY: proxyUrl }).catch(() => undefined) + expect(options.dispatcher).toBeInstanceOf(ProxyAgent) }) - it("sets proxy agent when http_proxy env variable is defined", async () => { + it("sets proxy dispatcher when http_proxy env variable is defined", async () => { const proxyUrl = "http://localhost:30002/" + const abortController = new AbortController() + abortController.abort() - await proxy.start() await server.start({}) - let options: node_fetch.RequestInit = { agent: undefined } - await api(url, options, true, { http_proxy: proxyUrl }) - let agent = options.agent as HttpProxyAgent - expect(agent["proxy"].href).toBe(proxyUrl) + let options = { method: "GET", dispatcher: undefined, signal: abortController.signal } + await api(url, options, true, { http_proxy: proxyUrl }).catch(() => undefined) + expect(options.dispatcher).toBeInstanceOf(ProxyAgent) }) }) diff --git a/source/api/fetch.ts b/source/api/fetch.ts index 7913d85d6..62af00584 100644 --- a/source/api/fetch.ts +++ b/source/api/fetch.ts @@ -1,10 +1,12 @@ -import { debug } from "../debug" -import * as node_fetch from "node-fetch" +import { fetch as undiciFetch, Headers, ProxyAgent } from "undici" +import type { Request, RequestInit, Response } from "undici" +import AsyncRetry from "async-retry" -import { HttpProxyAgent } from "http-proxy-agent" -import { HttpsProxyAgent } from "https-proxy-agent" +import { debug } from "../debug" -import AsyncRetry from "async-retry" +export type FetchResponse = Omit & { + json(): Promise +} const d = debug("networking") declare const global: any @@ -12,7 +14,7 @@ declare const global: any const isJest = typeof jest !== "undefined" const warn = isJest ? () => "" : console.warn -const shouldRetryRequest = (res: node_fetch.Response) => { +const shouldRetryRequest = (res: FetchResponse) => { // Don't retry 4xx errors other than 401. All 4xx errors can probably be ignored once // the Github API issue causing https://github.com/danger/peril/issues/440 is fixed return res.status === 401 || (res.status >= 500 && res.status <= 599) @@ -25,15 +27,11 @@ const shouldRetryRequest = (res: node_fetch.Response) => { * @param {fetch.RequestInit} [init] the usual options * @returns {Promise} network-y promise */ -export async function retryableFetch( - url: string | node_fetch.Request, - init: node_fetch.RequestInit -): Promise { +export async function retryableFetch(url: string | Request, init: RequestInit): Promise { const retries = isJest ? 1 : 3 return AsyncRetry( async (_, attempt) => { - const originalFetch = node_fetch.default - const res = await originalFetch(url, init) + const res = await undiciFetch(url, init) // Throwing an error will trigger a retry if (attempt <= retries && shouldRetryRequest(res)) { @@ -60,14 +58,15 @@ export async function retryableFetch( * @returns {Promise} network-y promise */ export function api( - url: string | node_fetch.Request, - init: node_fetch.RequestInit, + url: string | Request, + init: RequestInit, suppressErrorReporting?: boolean, processEnv: NodeJS.ProcessEnv = process.env -): Promise { +): Promise { const isTests = typeof jest !== "undefined" - if (isTests && !url.toString().includes("localhost")) { - const message = `No API calls in tests please: ${url}` + const requestUrl = typeof url === "string" ? url : url.url + if (isTests && !requestUrl.includes("localhost")) { + const message = `No API calls in tests please: ${requestUrl}` debugger throw new Error(message) } @@ -82,18 +81,14 @@ export function api( const showToken = processEnv["DANGER_VERBOSE_SHOW_TOKEN"] const token = processEnv["DANGER_GITHUB_API_TOKEN"] || processEnv["GITHUB_TOKEN"] - if (init.headers) { - for (const prop in init.headers) { - if (init.headers.hasOwnProperty(prop)) { - // Don't show the token for normal verbose usage - if (init.headers[prop].includes(token) && !showToken) { - output.push("-H", `"${prop}: [API TOKEN]"`) - continue - } - output.push("-H", `"${prop}: ${init.headers[prop]}"`) - } + new Headers(init.headers).forEach((value, prop) => { + // Don't show the token for normal verbose usage + if (token && value.includes(token) && !showToken) { + output.push("-H", `"${prop}: [API TOKEN]"`) + return } - } + output.push("-H", `"${prop}: ${value}"`) + }) if (init.method === "POST") { // const body:string = init.body @@ -107,16 +102,15 @@ export function api( d(output.join(" ")) } - let agent = init.agent + let dispatcher = init.dispatcher const proxy = processEnv["HTTPS_PROXY"] || processEnv["https_proxy"] || processEnv["HTTP_PROXY"] || processEnv["http_proxy"] - if (!agent && proxy) { - let secure = url.toString().startsWith("https") - init.agent = secure ? new HttpsProxyAgent(proxy) : new HttpProxyAgent(proxy) + if (!dispatcher && proxy) { + init.dispatcher = new ProxyAgent(proxy) } - return retryableFetch(url, init).then(async (response: node_fetch.Response) => { + return retryableFetch(url, init).then(async (response: FetchResponse) => { // Handle failing errors if (!suppressErrorReporting && !response.ok) { // we should not modify the response when an error occur to allow body stream to be read again if needed diff --git a/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts b/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts index 648dea442..9b09cd601 100644 --- a/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts +++ b/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts @@ -1,12 +1,10 @@ import { debug } from "../../debug" -import * as node_fetch from "node-fetch" -import { Agent } from "http" -import { HttpsProxyAgent } from "https-proxy-agent" import { URLSearchParams } from "url" import { Env } from "../../ci_source/ci_source" import { dangerIDToString } from "../../runner/templates/bitbucketCloudTemplate" import { api as fetch } from "../../api/fetch" +import type { FetchResponse } from "../../api/fetch" import { BitBucketCloudPagedResponse, BitBucketCloudPRDSL, @@ -385,15 +383,6 @@ export class BitBucketCloudAPI implements BitBucketCloudAPIDSL { private performAPI = (url: string, headers: any = {}, body: any = {}, method: string, suppressErrors?: boolean) => { this.d(`${method} ${url}`) - // Allow using a proxy configured through environmental variables - // Remember that to avoid the error "Error: self signed certificate in certificate chain" - // you should also do: "export NODE_TLS_REJECT_UNAUTHORIZED=0". See: https://github.com/request/request/issues/2061 - let agent: Agent | undefined = undefined - let proxy = process.env.http_proxy || process.env.https_proxy - if (proxy) { - agent = new HttpsProxyAgent(proxy) - } - return this.fetch( url, { @@ -403,26 +392,25 @@ export class BitBucketCloudAPI implements BitBucketCloudAPIDSL { "Content-Type": "application/json", ...headers, }, - agent, }, suppressErrors ) } - get = (url: string, headers: any = {}, suppressErrors?: boolean): Promise => + get = (url: string, headers: any = {}, suppressErrors?: boolean): Promise => this.api(url, headers, null, "GET", suppressErrors) - post = (url: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => + post = (url: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => this.api(url, headers, JSON.stringify(body), "POST", suppressErrors) - put = (url: string, headers: any = {}, body: any = {}): Promise => + put = (url: string, headers: any = {}, body: any = {}): Promise => this.api(url, headers, JSON.stringify(body), "PUT") - delete = (url: string, headers: any = {}, body: any = {}): Promise => + delete = (url: string, headers: any = {}, body: any = {}): Promise => this.api(url, headers, JSON.stringify(body), "DELETE") } -function throwIfNotOk(res: node_fetch.Response) { +function throwIfNotOk(res: FetchResponse) { if (!res.ok) { let message = `${res.status} - ${res.statusText}` if (res.status >= 400 && res.status < 500) { diff --git a/source/platforms/bitbucket_server/BitBucketServerAPI.ts b/source/platforms/bitbucket_server/BitBucketServerAPI.ts index 948e23874..cb2cea375 100644 --- a/source/platforms/bitbucket_server/BitBucketServerAPI.ts +++ b/source/platforms/bitbucket_server/BitBucketServerAPI.ts @@ -1,7 +1,4 @@ import { debug } from "../../debug" -import * as node_fetch from "node-fetch" -import { Agent } from "http" -import { HttpsProxyAgent } from "https-proxy-agent" import { BitBucketServerPRDSL, @@ -20,6 +17,7 @@ import { Comment } from "../platform" import { Env } from "../../ci_source/ci_source" import { dangerIDToString } from "../../runner/templates/bitbucketServerTemplate" import { api as fetch } from "../../api/fetch" +import type { FetchResponse } from "../../api/fetch" // Note that there are parts of this class which don't seem to be // used by Danger, they are exposed for Peril support. @@ -348,15 +346,6 @@ export class BitBucketServerAPI implements BitBucketServerAPIDSL { const url = `${this.repoCredentials.host}/${path}` this.d(`${method} ${url}`) - // Allow using a proxy configured through environmental variables - // Remember that to avoid the error "Error: self signed certificate in certificate chain" - // you should also do: "export NODE_TLS_REJECT_UNAUTHORIZED=0". See: https://github.com/request/request/issues/2061 - let agent: Agent | undefined = undefined - let proxy = process.env.http_proxy || process.env.https_proxy - if (proxy) { - agent = new HttpsProxyAgent(proxy) - } - return this.fetch( url, { @@ -366,26 +355,25 @@ export class BitBucketServerAPI implements BitBucketServerAPIDSL { "Content-Type": "application/json", ...headers, }, - agent, }, suppressErrors ) } - get = (path: string, headers: any = {}, suppressErrors?: boolean): Promise => + get = (path: string, headers: any = {}, suppressErrors?: boolean): Promise => this.api(path, headers, null, "GET", suppressErrors) - post = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => + post = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => this.api(path, headers, JSON.stringify(body), "POST", suppressErrors) - put = (path: string, headers: any = {}, body: any = {}): Promise => + put = (path: string, headers: any = {}, body: any = {}): Promise => this.api(path, headers, JSON.stringify(body), "PUT") - delete = (path: string, headers: any = {}, body: any = {}): Promise => + delete = (path: string, headers: any = {}, body: any = {}): Promise => this.api(path, headers, JSON.stringify(body), "DELETE") } -function throwIfNotOk(res: node_fetch.Response) { +function throwIfNotOk(res: FetchResponse) { if (!res.ok) { let message = `${res.status} - ${res.statusText}` if (res.status >= 400 && res.status < 500) { diff --git a/source/platforms/github/GitHubAPI.ts b/source/platforms/github/GitHubAPI.ts index b5effde8a..9ca905152 100644 --- a/source/platforms/github/GitHubAPI.ts +++ b/source/platforms/github/GitHubAPI.ts @@ -1,11 +1,11 @@ import { Octokit as GitHubNodeAPI } from "@octokit/rest" import { debug } from "../../debug" -import * as node_fetch from "node-fetch" import parse from "parse-link-header" import { GitHubPRDSL, GitHubIssueComment, GitHubUser } from "../../dsl/GitHubDSL" import { dangerIDToString } from "../../runner/templates/githubIssueTemplate" import { api as fetch } from "../../api/fetch" +import type { FetchResponse } from "../../api/fetch" import { RepoMetaData } from "../../dsl/RepoMetaData" import { CheckOptions } from "./comms/checks/resultsToCheck" @@ -307,9 +307,9 @@ export class GitHubAPI { * Read response header and locate next page for pagination via link header. * If not found, will return -1. * - * @param response Github API response sent via node-fetch + * @param response Github API response sent via undici */ - const getNextPageFromLinkHeader = (response: node_fetch.Response): number => { + const getNextPageFromLinkHeader = (response: FetchResponse): number => { const linkHeader = response.headers.get("link") if (!linkHeader) { this.d(`getNextPageFromLinkHeader:: Given response does not contain link header for pagination`) @@ -590,11 +590,11 @@ ${file.patch} ) } - get = (path: string, headers: any = {}): Promise => this.api(path, headers, null, "GET") + get = (path: string, headers: any = {}): Promise => this.api(path, headers, null, "GET") - post = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => + post = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => this.api(path, headers, JSON.stringify(body), "POST", suppressErrors) - patch = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => + patch = (path: string, headers: any = {}, body: any = {}, suppressErrors?: boolean): Promise => this.api(path, headers, JSON.stringify(body), "PATCH", suppressErrors) } diff --git a/source/platforms/github/comms/checks/githubAppSupport.ts b/source/platforms/github/comms/checks/githubAppSupport.ts index b4f0bed13..2b8265d47 100644 --- a/source/platforms/github/comms/checks/githubAppSupport.ts +++ b/source/platforms/github/comms/checks/githubAppSupport.ts @@ -1,5 +1,5 @@ import * as jwt from "jsonwebtoken" -import fetch from "node-fetch" +import { fetch } from "undici" // Step 1 @@ -35,6 +35,12 @@ const requestAccessTokenForInstallation = (appID: string, installationID: number }) } +const isInstallationAccessToken = (credentials: unknown): credentials is { token: string } => + typeof credentials === "object" && + credentials !== null && + "token" in credentials && + typeof credentials.token === "string" + /** Generates a temporary access token for an app's installation, 5m long */ export const getAccessTokenForInstallation = async (appID: string, installationID: number, key: string) => { const newToken = await requestAccessTokenForInstallation(appID, installationID, key) @@ -43,5 +49,8 @@ export const getAccessTokenForInstallation = async (appID: string, installationI console.error(`Could not get an access token for ${installationID}`) console.error(`GitHub returned: ${JSON.stringify(credentials)}`) } - return credentials.token as string + if (!isInstallationAccessToken(credentials)) { + throw new Error(`GitHub did not return an installation access token for ${installationID}`) + } + return credentials.token } diff --git a/source/platforms/gitlab/_tests/_fetch_polyfill.ts b/source/platforms/gitlab/_tests/_fetch_polyfill.ts deleted file mode 100644 index 95fc089ae..000000000 --- a/source/platforms/gitlab/_tests/_fetch_polyfill.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Nock does not support native fetch until 4.0.0 release which at the time of writing is in beta. -// Furthermore it is currently unsure if 4.0.0 will contain support for recording fixtures. -// Until nock is updated >= 4.0.0 the polyfill is needed when testing against frameworks leveraging native fetch. - -import fetch from "node-fetch" - -let global = globalThis as any -global.fetch = fetch diff --git a/source/platforms/gitlab/_tests/_gitlab_api.test.ts b/source/platforms/gitlab/_tests/_gitlab_api.test.ts index 6101c9a35..d4f8d45e4 100644 --- a/source/platforms/gitlab/_tests/_gitlab_api.test.ts +++ b/source/platforms/gitlab/_tests/_gitlab_api.test.ts @@ -3,7 +3,6 @@ import nock, { Definition } from "nock" import { default as GitLabAPI, getGitLabAPICredentialsFromEnv } from "../GitLabAPI" import { resolve } from "path" import { readFileSync } from "fs" -import "./_fetch_polyfill" const nockBack = nock.back nockBack.fixtures = __dirname + "/fixtures" diff --git a/yarn.lock b/yarn.lock index 6fbb86e0c..f9c6e8ed3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1484,6 +1484,18 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@mswjs/interceptors@^0.41.0": + version "0.41.9" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.41.9.tgz#9d90bbd60d1ddc30dbcbb827a9bb2e470493530d" + integrity sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.4.3" + strict-event-emitter "^0.5.1" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" @@ -1617,6 +1629,24 @@ dependencies: "@octokit/openapi-types" "^23.0.1" +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + "@pkgr/core@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" @@ -1891,14 +1921,6 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== -"@types/node-fetch@^2.5.12": - version "2.6.12" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" - integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== - dependencies: - "@types/node" "*" - form-data "^4.0.0" - "@types/node@*": version "22.13.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.10.tgz#df9ea358c5ed991266becc3109dc2dc9125d77e4" @@ -2278,11 +2300,6 @@ async-retry@1.3.3: dependencies: retry "0.13.1" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" @@ -2699,13 +2716,6 @@ colors@1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - commander@^2.16.0, commander@^2.18.0, commander@^2.20.3, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2906,11 +2916,6 @@ degenerator@^5.0.0: escodegen "^2.1.0" esprima "^4.0.1" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - dependency-tree@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-9.0.0.tgz#9288dd6daf35f6510c1ea30d9894b75369aa50a2" @@ -3208,16 +3213,6 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" -es-set-tostringtag@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" - integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - has-tostringtag "^1.0.2" - hasown "^2.0.2" - escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -3608,16 +3603,6 @@ flow-bin@^0.77.0: resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.77.0.tgz#4e5c93929f289a0c28e08fb361a9734944a11297" integrity sha512-ejne8bZMAx1/H3J3icWEVZC2GkCZeesclnFEb8eAcb1WCs/CCep/0T5A2x+BssHzC2w/x57IDZWHuy2Vj200Kw== -form-data@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" - integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - es-set-tostringtag "^2.1.0" - mime-types "^2.1.12" - from2@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -3701,7 +3686,7 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== -get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -3900,18 +3885,11 @@ has-flag@^5.0.1: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-5.0.1.tgz#5483db2ae02a472d1d0691462fc587d1843cd940" integrity sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA== -has-symbols@^1.0.3, has-symbols@^1.1.0: +has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - has@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" @@ -3939,7 +3917,7 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1, http-proxy-agent@^7.0.2: +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== @@ -3955,7 +3933,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.6: +https-proxy-agent@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== @@ -4186,6 +4164,11 @@ is-interactive@^2.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + is-npm@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-6.0.0.tgz#b59e75e8915543ca5d881ecff864077cba095261" @@ -5172,7 +5155,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@2.1.35, mime-types@^2.1.12: +mime-types@2.1.35: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -5298,12 +5281,12 @@ new-github-release-url@2.0.0: dependencies: type-fest "^2.5.1" -nock@^13.2.0: - version "13.5.6" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.6.tgz#5e693ec2300bbf603b61dae6df0225673e6c4997" - integrity sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ== +nock@^14.0.15: + version "14.0.15" + resolved "https://registry.yarnpkg.com/nock/-/nock-14.0.15.tgz#23f9978fb20d8b3607dc263f4978cb89648f550b" + integrity sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg== dependencies: - debug "^4.1.0" + "@mswjs/interceptors" "^0.41.0" json-stringify-safe "^5.0.1" propagate "^2.0.0" @@ -5319,7 +5302,7 @@ node-cleanup@^2.1.2: resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw== -node-fetch@^2.6.0, node-fetch@^2.6.6, node-fetch@^2.6.7: +node-fetch@^2.6.0, node-fetch@^2.6.6: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -5485,6 +5468,11 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +outvariant@^1.4.0, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== + override-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/override-require/-/override-require-1.1.1.tgz#6ae22fadeb1f850ffb0cf4c20ff7b87e5eb650df" @@ -6586,6 +6574,11 @@ stream-to-array@^2.3.0: dependencies: any-promise "^1.1.0" +strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + string-argv@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"