diff --git a/src/commands/changelogs.ts b/src/commands/changelogs.ts index e1a7207ed..31d5d11c2 100644 --- a/src/commands/changelogs.ts +++ b/src/commands/changelogs.ts @@ -2,7 +2,7 @@ import { Args, Flags } from '@oclif/core'; import BaseCommand from '../lib/baseCommand.js'; import { githubFlag, keyFlag } from '../lib/flags.js'; -import syncDocsPath from '../lib/syncDocsPath.js'; +import syncDocsPath from '../lib/syncDocsPath.legacy.js'; export default class ChangelogsCommand extends BaseCommand { // we need this as a const for syncDocsPath diff --git a/src/lib/baseCommand.ts b/src/lib/baseCommand.ts index d965f3526..755e65924 100644 --- a/src/lib/baseCommand.ts +++ b/src/lib/baseCommand.ts @@ -9,7 +9,7 @@ import chalk from 'chalk'; import debugPkg from 'debug'; import { isGHA, isTest } from './isCI.js'; -import { handleAPIv2Res, readmeAPIv2Fetch, type FilePathDetails } from './readmeAPIFetch.js'; +import { handleAPIv2Res, readmeAPIv2Fetch } from './readmeAPIFetch.js'; type Flags = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>; type Args = Interfaces.InferredArgs; @@ -116,19 +116,15 @@ export default abstract class BaseCommand extends /** * Wrapper around `handleAPIv2Res` that binds the context of the class to the function. */ - public async handleAPIRes(res: Response) { - return handleAPIv2Res.call(this, res); + public async handleAPIRes(...args: Parameters) { + return handleAPIv2Res.call(this, ...args); } /** * Wrapper around `readmeAPIv2Fetch` that binds the context of the class to the function. */ - public async readmeAPIFetch( - pathname: string, - options: RequestInit = { headers: new Headers() }, - fileOpts: FilePathDetails = { filePath: '', fileType: false }, - ) { - return readmeAPIv2Fetch.call(this, pathname, options, fileOpts); + public async readmeAPIFetch(...args: Parameters) { + return readmeAPIv2Fetch.call(this, ...args); } async runCreateGHAHook(opts: CreateGHAHookOptsInClass) { diff --git a/src/lib/readmeAPIFetch.ts b/src/lib/readmeAPIFetch.ts index 4bd504274..64e2d20dc 100644 --- a/src/lib/readmeAPIFetch.ts +++ b/src/lib/readmeAPIFetch.ts @@ -19,7 +19,7 @@ const SUCCESS_NO_CONTENT = 204; * This contains a few pieces of information about a file so * we can properly construct a source URL for it. */ -export interface FilePathDetails { +interface FilePathDetails { /** The URL or local file path */ filePath: string; /** This is derived from the `oas-normalize` `type` property. */ @@ -348,10 +348,30 @@ export async function handleAPIv1Res(res: Response, rejectOnJsonError = true) { * * If we receive non-JSON responses, we consider them errors and throw them. */ -export async function handleAPIv2Res(this: T, res: Response) { +export async function handleAPIv2Res( + this: T, + res: Response, + /** + * If we're making a request where we don't care about the body (e.g. a HEAD or DELETE request), + * we can skip parsing the JSON body using this flag. + */ + skipJsonParsing = false, +) { const contentType = res.headers.get('content-type') || ''; const extension = mime.extension(contentType) || contentType.includes('json') ? 'json' : false; - if (extension === 'json') { + if (res.status === SUCCESS_NO_CONTENT) { + // to prevent a memory leak, we should still consume the response body? even though we don't use it? + // https://x.com/cramforce/status/1762142087930433999 + const body = await res.text(); + this.debug(`received status code ${res.status} from ${res.url} with no content: ${body}`); + return {}; + } else if (skipJsonParsing) { + // to prevent a memory leak, we should still consume the response body? even though we don't use it? + // https://x.com/cramforce/status/1762142087930433999 + const body = await res.text(); + this.debug(`received status code ${res.status} from ${res.url} and not parsing JSON b/c of flag: ${body}`); + return {}; + } else if (extension === 'json') { // TODO: type this better // eslint-disable-next-line @typescript-eslint/no-explicit-any const body = (await res.json()) as any; @@ -361,10 +381,6 @@ export async function handleAPIv2Res(this: T, res: Response) } return body; } - if (res.status === SUCCESS_NO_CONTENT) { - this.debug(`received status code ${res.status} from ${res.url} with no content`); - return {}; - } // If we receive a non-JSON response, it's likely an error. // Let's debug the raw response body and throw it. diff --git a/src/lib/syncDocsPath.ts b/src/lib/syncDocsPath.legacy.ts similarity index 98% rename from src/lib/syncDocsPath.ts rename to src/lib/syncDocsPath.legacy.ts index 30e586100..ba001861d 100644 --- a/src/lib/syncDocsPath.ts +++ b/src/lib/syncDocsPath.legacy.ts @@ -144,6 +144,8 @@ function sortFiles(filePaths: string[]): ReadDocMetadata[] { * Takes a path (either to a directory of files or to a single file) * and syncs those (either via POST or PUT) to ReadMe. * @returns A promise-wrapped string with the results + * + * @deprecated This is for APIv1 only. Use `syncDocsPath.ts` instead, if possible. */ export default async function syncDocsPath( this: ChangelogsCommand,