From 07a1896e69d8f07d4cbe4f9ccd0ed52d8f6f1242 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Tue, 17 Jun 2025 16:05:49 +0700 Subject: [PATCH] feat: web only retry query errors on certain HTTP statuses like ky --- apps/web/src/app/app/app-index.tsx | 2 +- .../[consumerId]/app-consumer-index.tsx | 3 +- .../app/app/consumers/app-consumers-index.tsx | 2 +- .../[project-name]/app-project-index.tsx | 3 +- .../src/app/marketplace/marketplace-index.tsx | 2 +- .../marketplace-project-index.tsx | 2 +- apps/web/src/lib/query-client.ts | 76 ++++++++++++++++++- readme.md | 3 - 8 files changed, 81 insertions(+), 12 deletions(-) diff --git a/apps/web/src/app/app/app-index.tsx b/apps/web/src/app/app/app-index.tsx index ed7844a3..d3b40804 100644 --- a/apps/web/src/app/app/app-index.tsx +++ b/apps/web/src/app/app/app-index.tsx @@ -1,11 +1,11 @@ 'use client' -import { useInfiniteQuery } from '@tanstack/react-query' import Link from 'next/link' import useInfiniteScroll from 'react-infinite-scroll-hook' import { useAuthenticatedAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' +import { useInfiniteQuery } from '@/lib/query-client' export function AppIndex() { const ctx = useAuthenticatedAgentic() diff --git a/apps/web/src/app/app/consumers/[consumerId]/app-consumer-index.tsx b/apps/web/src/app/app/consumers/[consumerId]/app-consumer-index.tsx index 556abd1d..e6e25f75 100644 --- a/apps/web/src/app/app/consumers/[consumerId]/app-consumer-index.tsx +++ b/apps/web/src/app/app/consumers/[consumerId]/app-consumer-index.tsx @@ -1,9 +1,8 @@ 'use client' -import { useQuery } from '@tanstack/react-query' - import { useAuthenticatedAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' +import { useQuery } from '@/lib/query-client' export function AppConsumerIndex({ consumerId }: { consumerId: string }) { const ctx = useAuthenticatedAgentic() diff --git a/apps/web/src/app/app/consumers/app-consumers-index.tsx b/apps/web/src/app/app/consumers/app-consumers-index.tsx index 234baa93..2b1e8d03 100644 --- a/apps/web/src/app/app/consumers/app-consumers-index.tsx +++ b/apps/web/src/app/app/consumers/app-consumers-index.tsx @@ -1,11 +1,11 @@ 'use client' -import { useInfiniteQuery } from '@tanstack/react-query' import Link from 'next/link' import useInfiniteScroll from 'react-infinite-scroll-hook' import { useAuthenticatedAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' +import { useInfiniteQuery } from '@/lib/query-client' export function AppConsumersIndex() { const ctx = useAuthenticatedAgentic() diff --git a/apps/web/src/app/app/projects/[namespace]/[project-name]/app-project-index.tsx b/apps/web/src/app/app/projects/[namespace]/[project-name]/app-project-index.tsx index 8c1ccb8f..a388cc06 100644 --- a/apps/web/src/app/app/projects/[namespace]/[project-name]/app-project-index.tsx +++ b/apps/web/src/app/app/projects/[namespace]/[project-name]/app-project-index.tsx @@ -1,9 +1,8 @@ 'use client' -import { useQuery } from '@tanstack/react-query' - import { useAuthenticatedAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' +import { useQuery } from '@/lib/query-client' export function AppProjectIndex({ projectIdentifier diff --git a/apps/web/src/app/marketplace/marketplace-index.tsx b/apps/web/src/app/marketplace/marketplace-index.tsx index aa41084f..61cf0378 100644 --- a/apps/web/src/app/marketplace/marketplace-index.tsx +++ b/apps/web/src/app/marketplace/marketplace-index.tsx @@ -1,11 +1,11 @@ 'use client' -import { useInfiniteQuery } from '@tanstack/react-query' import Link from 'next/link' import useInfiniteScroll from 'react-infinite-scroll-hook' import { useAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' +import { useInfiniteQuery } from '@/lib/query-client' export function MarketplaceIndex() { const ctx = useAgentic() diff --git a/apps/web/src/app/marketplace/projects/[namespace]/[project-name]/marketplace-project-index.tsx b/apps/web/src/app/marketplace/projects/[namespace]/[project-name]/marketplace-project-index.tsx index c7cb8eed..72cac1e3 100644 --- a/apps/web/src/app/marketplace/projects/[namespace]/[project-name]/marketplace-project-index.tsx +++ b/apps/web/src/app/marketplace/projects/[namespace]/[project-name]/marketplace-project-index.tsx @@ -1,7 +1,6 @@ 'use client' import { assert, omit } from '@agentic/platform-core' -import { useQuery } from '@tanstack/react-query' import { redirect } from 'next/navigation' import { useCallback, useEffect } from 'react' import { useSearchParam } from 'react-use' @@ -10,6 +9,7 @@ import { useAgentic } from '@/components/agentic-provider' import { LoadingIndicator } from '@/components/loading-indicator' import { Button } from '@/components/ui/button' import { toast, toastError } from '@/lib/notifications' +import { useQuery } from '@/lib/query-client' export function MarketplaceProjectIndex({ projectIdentifier diff --git a/apps/web/src/lib/query-client.ts b/apps/web/src/lib/query-client.ts index 9f692601..53656c2b 100644 --- a/apps/web/src/lib/query-client.ts +++ b/apps/web/src/lib/query-client.ts @@ -1,3 +1,77 @@ -import { QueryClient } from '@tanstack/react-query' +import { + type DefaultError, + type InfiniteData, + QueryClient, + type QueryKey, + useInfiniteQuery as useInfiniteQueryBase, + useQuery as useQueryBase +} from '@tanstack/react-query' +import { HTTPError } from 'ky' export const queryClient = new QueryClient() + +const retryStatusCodes = new Set([408, 413, 429, 500, 502, 503, 504]) + +function retry(failureCount: number, error: any): boolean { + if (error instanceof HTTPError) { + const { status } = error.response + if (!retryStatusCodes.has(status)) { + return false + } + } + + return failureCount < 3 +} + +export function useQuery< + TQueryFnData = unknown, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey +>( + opts: Parameters< + typeof useQueryBase + >[0] +): ReturnType> { + return useQueryBase({ + retry, + ...opts + }) +} + +export function useInfiniteQuery< + TQueryFnData, + TError = DefaultError, + TData = InfiniteData, + TQueryKey extends QueryKey = QueryKey, + TPageParam = unknown +>( + opts: Parameters< + typeof useInfiniteQueryBase< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + > + >[0] +): ReturnType< + typeof useInfiniteQueryBase< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + > +> { + return useInfiniteQueryBase< + TQueryFnData, + TError, + TData, + TQueryKey, + TPageParam + >({ + retry, + ...opts + }) +} diff --git a/readme.md b/readme.md index 0795fa1e..d8eb0fb5 100644 --- a/readme.md +++ b/readme.md @@ -20,9 +20,6 @@ - handle unauthenticated checkout flow => auth and then redirect to create a checkout session - will need a `redirect` url for `/login` and `/signup` - `/marketplace/projects/@{projectIdentifier}/checkout?plan={plan}` - - data loading / react-query - - don't retry queries on 401/403 - - mimic logic from `ky` for automatic retries - stripe - stripe checkout - stripe billing portal