(
schema: TResponseSchema,
url: string,
requestInit?: RequestInit,
options?: {
errorMessage?: string;
optional?: TOptional;
},
retryCount = 0
)
| 974 | } |
| 975 | |
| 976 | async function zodfetch<TResponseSchema extends z.ZodTypeAny, TOptional extends boolean = false>( |
| 977 | schema: TResponseSchema, |
| 978 | url: string, |
| 979 | requestInit?: RequestInit, |
| 980 | options?: { |
| 981 | errorMessage?: string; |
| 982 | optional?: TOptional; |
| 983 | }, |
| 984 | retryCount = 0 |
| 985 | ): Promise< |
| 986 | TOptional extends true ? z.infer<TResponseSchema> | undefined : z.infer<TResponseSchema> |
| 987 | > { |
| 988 | try { |
| 989 | const response = await fetch(url, requestInitWithCache(requestInit)); |
| 990 | |
| 991 | if ( |
| 992 | (!requestInit || requestInit.method === "GET") && |
| 993 | response.status === 404 && |
| 994 | options?.optional |
| 995 | ) { |
| 996 | // @ts-ignore |
| 997 | return; |
| 998 | } |
| 999 | |
| 1000 | //rate limit, so we want to reschedule |
| 1001 | if (response.status === 429) { |
| 1002 | //unix timestamp in milliseconds |
| 1003 | const retryAfter = response.headers.get("x-ratelimit-reset"); |
| 1004 | if (retryAfter) { |
| 1005 | throw new AutoYieldRateLimitError(parseInt(retryAfter)); |
| 1006 | } |
| 1007 | } |
| 1008 | |
| 1009 | if (response.status >= 400 && response.status < 500) { |
| 1010 | const body = await response.json(); |
| 1011 | |
| 1012 | throw new Error(body.error); |
| 1013 | } |
| 1014 | |
| 1015 | if (response.status >= 500 && retryCount < MAX_RETRIES) { |
| 1016 | // retry with exponential backoff and jitter |
| 1017 | const delay = exponentialBackoff(retryCount + 1); |
| 1018 | |
| 1019 | await new Promise((resolve) => setTimeout(resolve, delay)); |
| 1020 | |
| 1021 | return zodfetch(schema, url, requestInit, options, retryCount + 1); |
| 1022 | } |
| 1023 | |
| 1024 | if (response.status !== 200) { |
| 1025 | throw new Error( |
| 1026 | options?.errorMessage ?? `Failed to fetch ${url}, got status code ${response.status}` |
| 1027 | ); |
| 1028 | } |
| 1029 | |
| 1030 | const jsonBody = await response.json(); |
| 1031 | |
| 1032 | return schema.parse(jsonBody); |
| 1033 | } catch (error) { |
no test coverage detected
searching dependent graphs…