diff --git a/app/lib/http.server.ts b/app/lib/http.server.ts new file mode 100644 index 0000000..6eccdec --- /dev/null +++ b/app/lib/http.server.ts @@ -0,0 +1,41 @@ +import axiosFactory from "axios"; + +const retryDelay = 1000; + +export const http = axiosFactory.create({ + headers: { + "x-agent": "automod", + }, +}); + +http.interceptors.response.use(undefined, function axiosRetryInterceptor(err) { + const config = err.config; + + console.error({ + status: err.response?.status, + data: JSON.stringify(err.response?.data), + }); + + if ( + err.response?.status && + (err.response.status === 429 || err.response.status >= 500) && + !config.__retryCount + ) { + config.__retryCount = 0; + } + + if (config.__retryCount < 3) { + // Max retry limit + config.__retryCount += 1; + const backoffDelay = 2 ** config.__retryCount * retryDelay; + console.warn(`Received HTTP ${err.response.status}, retrying in ${backoffDelay}ms`); + + return new Promise((resolve) => { + setTimeout(() => { + resolve(http(config)); + }, backoffDelay); + }); + } + + return Promise.reject(err); +}); diff --git a/app/lib/neynar.server.ts b/app/lib/neynar.server.ts index 840095b..a16bdae 100644 --- a/app/lib/neynar.server.ts +++ b/app/lib/neynar.server.ts @@ -5,7 +5,11 @@ import { FollowResponseUser, Reaction } from "@neynar/nodejs-sdk/build/neynar-ap import { CastWithInteractions, Channel, User } from "@neynar/nodejs-sdk/build/neynar-api/v2"; import axios from "axios"; import { getSetCache, getSharedEnv } from "./utils.server"; -export const neynar = new NeynarAPIClient(process.env.NEYNAR_API_KEY!); +import { http } from "./http.server"; + +export const neynar = new NeynarAPIClient(process.env.NEYNAR_API_KEY!, { + axiosInstance: http, +}); export async function registerWebhook({ rootParentUrl }: { rootParentUrl: string }) { const webhook = await axios.get( diff --git a/app/lib/warpcast.server.ts b/app/lib/warpcast.server.ts index 054ef15..11ad25c 100644 --- a/app/lib/warpcast.server.ts +++ b/app/lib/warpcast.server.ts @@ -1,50 +1,13 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import axiosFactory from "axios"; import { Cast } from "@neynar/nodejs-sdk/build/neynar-api/v2"; import { db } from "./db.server"; import { Action, unlike } from "./validations.server"; import { neynar } from "./neynar.server"; import { getSetCache } from "./utils.server"; +import { http } from "./http.server"; const token = process.env.WARPCAST_TOKEN!; -export const http = axiosFactory.create({ - headers: { - "x-agent": "automod", - }, -}); - -http.interceptors.response.use(undefined, function axiosRetryInterceptor(err) { - const config = err.config; - - console.error({ - status: err.response?.status, - data: JSON.stringify(err.response?.data), - }); - - if ( - err.response?.status && - (err.response.status === 429 || err.response.status >= 500) && - !config.__retryCount - ) { - config.__retryCount = 0; - } - - if (config.__retryCount < 3) { - // Max retry limit - config.__retryCount += 1; - const backoffDelay = 2 ** config.__retryCount * 1000; // Exponential backoff - console.warn(`Received HTTP ${err.response.status}, retrying in ${backoffDelay}ms`); - - return new Promise((resolve) => { - setTimeout(() => { - resolve(http(config)); - }, backoffDelay); - }); - } - - return Promise.reject(err); -}); export async function getWarpcastChannelOwner(props: { channel: string }): Promise { const channel = await getWarpcastChannel(props); diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..6f27bb6 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: \ No newline at end of file