From d00102108039b171846be8693da5d0668afecceb Mon Sep 17 00:00:00 2001 From: wolfy1339 Date: Fri, 1 Dec 2023 18:07:27 -0500 Subject: [PATCH 1/2] feat: add types for the plugin --- src/error-request.ts | 17 +++++++++++++---- src/index.ts | 27 ++++++++++++++++++++++----- src/types.ts | 20 ++++++++++++++++++++ src/wrap-request.ts | 32 +++++++++++++++++++++++++------- test/retry.test.ts | 2 ++ 5 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 src/types.ts diff --git a/src/error-request.ts b/src/error-request.ts index da4a7a5d..c654855b 100644 --- a/src/error-request.ts +++ b/src/error-request.ts @@ -1,6 +1,13 @@ -// @ts-ignore +import type { RequestError } from "@octokit/request-error"; +import type { State, Octokit } from "./types"; +import type { EndpointDefaults } from "@octokit/types"; -export async function errorRequest(state, octokit, error, options) { +export async function errorRequest( + state: State, + octokit: Octokit, + error: RequestError, + options: Required, +) { if (!error.request || !error.request.request) { // address https://github.com/octokit/plugin-retry.js/issues/8 throw error; @@ -9,8 +16,10 @@ export async function errorRequest(state, octokit, error, options) { // retry all >= 400 && not doNotRetry if (error.status >= 400 && !state.doNotRetry.includes(error.status)) { const retries = - options.request.retries != null ? options.request.retries : state.retries; - const retryAfter = Math.pow((options.request.retryCount || 0) + 1, 2); + options.request?.retries != null + ? options.request.retries + : state.retries; + const retryAfter = Math.pow((options.request?.retryCount || 0) + 1, 2); throw octokit.retry.retryRequest(error, retries, retryAfter); } diff --git a/src/index.ts b/src/index.ts index 43e47afa..5d6b02f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,18 @@ -import { Octokit } from "@octokit/core"; +import type { Octokit as OctokitCore } from "@octokit/core"; import type { RequestError } from "@octokit/request-error"; - +import type { OctokitOptions } from "@octokit/core/dist-types/types.d"; import { errorRequest } from "./error-request"; import { wrapRequest } from "./wrap-request"; +import type { RetryOptions, State } from "./types"; +import type { WrapHook } from "before-after-hook"; + +import { VERSION } from "./version.js"; +import type { EndpointDefaults, OctokitResponse } from "@octokit/types"; -export const VERSION = "0.0.0-development"; +export { VERSION }; -export function retry(octokit: Octokit, octokitOptions: any) { - const state = Object.assign( +export function retry(octokit: OctokitCore, octokitOptions: OctokitOptions) { + const state: State = Object.assign( { enabled: true, retryAfterBaseValue: 1000, @@ -18,7 +23,13 @@ export function retry(octokit: Octokit, octokitOptions: any) { ); if (state.enabled) { + // @ts-expect-error octokit.hook.error("request", errorRequest.bind(null, state, octokit)); + // The types for `before-after-hook` do not let us only pass through a Promise return value + // the types expect that the function can return either a Promise of the response, or diectly return the response. + // This is due to the fact that `@octokit/request` uses aysnc functions + // Also, since we add the custom `retryCount` property to the request argument, the types are not compatible. + // @ts-expect-error octokit.hook.wrap("request", wrapRequest.bind(null, state, octokit)); } @@ -40,3 +51,9 @@ export function retry(octokit: Octokit, octokitOptions: any) { }; } retry.VERSION = VERSION; + +declare module "@octokit/core/dist-types/types.d" { + interface OctokitOptions { + retry?: RetryOptions; + } +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..48c3d863 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,20 @@ +import { Octokit as OctokitCore } from "@octokit/core"; +import type { RequestError } from "@octokit/request-error"; + +export type RetryOptions = { + enabled?: boolean; + doNotRetry?: number[]; + retries?: number; + retryAfterBaseValue?: number; +}; + +export type State = Required; +export type Octokit = OctokitCore & { + retry: { + retryRequest: ( + error: RequestError, + retries: number, + retryAfter: number, + ) => RequestError; + }; +}; diff --git a/src/wrap-request.ts b/src/wrap-request.ts index 28cadeff..5cacba11 100644 --- a/src/wrap-request.ts +++ b/src/wrap-request.ts @@ -1,10 +1,24 @@ -// @ts-nocheck +// @ts-expect-error import Bottleneck from "bottleneck/light"; +import type TBottleneck from "bottleneck"; import { RequestError } from "@octokit/request-error"; import { errorRequest } from "./error-request"; +import type { Octokit, State } from "./types"; +import type { EndpointDefaults, OctokitResponse } from "@octokit/types"; -export async function wrapRequest(state, octokit, request, options) { - const limiter = new Bottleneck(); +type Request = ( + request: Request, + options: Required, + ) => Promise>; +export async function wrapRequest( + state: State, + octokit: Octokit, + request: ( + options: Required, + ) => Promise>, + options: Required, +) { + const limiter: TBottleneck = new Bottleneck(); limiter.on("failed", function (error, info) { const maxRetries = ~~error.request.request.retries; @@ -19,16 +33,20 @@ export async function wrapRequest(state, octokit, request, options) { }); return limiter.schedule( + // @ts-expect-error requestWithGraphqlErrorHandling.bind(null, state, octokit, request), options, ); } async function requestWithGraphqlErrorHandling( - state, - octokit, - request, - options, + state: State, + octokit: Octokit, + request: ( + request: Request, + options: Required, + ) => Promise>, + options: Required, ) { const response = await request(request, options); diff --git a/test/retry.test.ts b/test/retry.test.ts index 41a27a3e..d3903672 100644 --- a/test/retry.test.ts +++ b/test/retry.test.ts @@ -426,6 +426,7 @@ describe("errorRequest", function () { delete error.request; try { + // @ts-expect-error await errorRequest(state, octokit, error, errorOptions); expect(1).not.toBe(1); } catch (e: any) { @@ -454,6 +455,7 @@ describe("errorRequest", function () { const error = new RequestError("Internal server error", 500, errorOptions); try { + // @ts-expect-error await errorRequest(state, octokit, error, errorOptions); expect(1).not.toBe(1); } catch (e: any) { From b6bace1565f454554aeb1c6494991d1a87d7554f Mon Sep 17 00:00:00 2001 From: wolfy1339 Date: Tue, 18 Mar 2025 16:34:05 -0400 Subject: [PATCH 2/2] correct some merge issues --- src/error-request.ts | 2 +- src/index.ts | 6 +++--- src/types.ts | 2 +- src/wrap-request.ts | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/error-request.ts b/src/error-request.ts index c654855b..1e225ed7 100644 --- a/src/error-request.ts +++ b/src/error-request.ts @@ -1,5 +1,5 @@ import type { RequestError } from "@octokit/request-error"; -import type { State, Octokit } from "./types"; +import type { State, Octokit } from "./types.js"; import type { EndpointDefaults } from "@octokit/types"; export async function errorRequest( diff --git a/src/index.ts b/src/index.ts index 551af1b4..33523f16 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ -import type { Octokit } from "@octokit/core"; +import type { Octokit as OctokitCore } from "@octokit/core"; import type { RequestError } from "@octokit/request-error"; import type { OctokitOptions } from "@octokit/core/types"; -import type { EndpointDefaults, OctokitResponse } from "@octokit/types"; import { VERSION } from "./version.js"; import { errorRequest } from "./error-request.js"; import { wrapRequest } from "./wrap-request.js"; +import type { RetryOptions, State } from "./types.js"; export { VERSION } from "./version.js"; export function retry(octokit: OctokitCore, octokitOptions: OctokitOptions) { @@ -49,7 +49,7 @@ export function retry(octokit: OctokitCore, octokitOptions: OctokitOptions) { } retry.VERSION = VERSION; -declare module "@octokit/core/dist-types/types.d" { +declare module "@octokit/core/types" { interface OctokitOptions { retry?: RetryOptions; } diff --git a/src/types.ts b/src/types.ts index 48c3d863..418f3832 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { Octokit as OctokitCore } from "@octokit/core"; +import type { Octokit as OctokitCore } from "@octokit/core"; import type { RequestError } from "@octokit/request-error"; export type RetryOptions = { diff --git a/src/wrap-request.ts b/src/wrap-request.ts index edefd24e..bb37b9eb 100644 --- a/src/wrap-request.ts +++ b/src/wrap-request.ts @@ -7,9 +7,9 @@ import type { Octokit, State } from "./types.js"; import type { EndpointDefaults, OctokitResponse } from "@octokit/types"; type Request = ( - request: Request, - options: Required, - ) => Promise>; + request: Request, + options: Required, +) => Promise>; export async function wrapRequest( state: State, octokit: Octokit,