diff --git a/components/item-act.js b/components/item-act.js index 5312e8bd..4eaa0f24 100644 --- a/components/item-act.js +++ b/components/item-act.js @@ -13,6 +13,7 @@ import { usePaidMutation } from './use-paid-mutation' import { ACT_MUTATION } from '@/fragments/paidAction' import { meAnonSats } from '@/lib/apollo' import { BoostItemInput } from './adv-post-form' +import { useWallet } from '../wallets' const defaultTips = [100, 1000, 10_000, 100_000] @@ -250,12 +251,12 @@ export function useAct ({ query = ACT_MUTATION, ...options } = {}) { } export function useZap () { + const wallet = useWallet() const act = useAct() - const { me } = useMe() const strike = useLightning() const toaster = useToast() - return useCallback(async ({ item, abortSignal }) => { + return useCallback(async ({ item, me, abortSignal }) => { const meSats = (item?.meSats || 0) // add current sats to next tip since idempotent zaps use desired total zap not difference @@ -267,7 +268,8 @@ export function useZap () { try { await abortSignal.pause({ me, amount: sats }) strike() - const { error } = await act({ variables, optimisticResponse }) + // batch zaps if wallet is enabled or using fee credits so they can be executed serially in a single request + const { error } = await act({ variables, optimisticResponse, context: { batch: !!wallet || me?.privates?.sats > sats } }) if (error) throw error } catch (error) { if (error instanceof ActCanceledError) { @@ -277,7 +279,7 @@ export function useZap () { const reason = error?.message || error?.toString?.() toaster.danger(reason) } - }, [act, me?.id, strike]) + }, [act, toaster, strike, !!wallet]) } export class ActCanceledError extends Error { diff --git a/lib/apollo.js b/lib/apollo.js index 53dd567a..98f975ae 100644 --- a/lib/apollo.js +++ b/lib/apollo.js @@ -1,4 +1,5 @@ -import { ApolloClient, InMemoryCache, HttpLink, makeVar } from '@apollo/client' +import { ApolloClient, InMemoryCache, HttpLink, makeVar, split } from '@apollo/client' +import { BatchHttpLink } from '@apollo/client/link/batch-http' import { decodeCursor, LIMIT } from './cursor' import { SSR } from './constants' @@ -28,8 +29,15 @@ export default function getApolloClient () { export const meAnonSats = {} function getClient (uri) { + const link = split( + // batch zaps if wallet is enabled so they can be executed serially in a single request + operation => operation.operationName === 'act' && operation.variables.act === 'TIP' && operation.getContext().batch, + new BatchHttpLink({ uri, batchInterval: 1000, batchDebounce: true, batchMax: 0, batchKey: op => op.variables.id }), + new HttpLink({ uri }) + ) + return new ApolloClient({ - link: new HttpLink({ uri }), + link, ssrMode: SSR, connectToDevTools: process.env.NODE_ENV !== 'production', cache: new InMemoryCache({ diff --git a/pages/api/graphql.js b/pages/api/graphql.js index 297bab09..7d41ee57 100644 --- a/pages/api/graphql.js +++ b/pages/api/graphql.js @@ -16,6 +16,7 @@ const apolloServer = new ApolloServer({ typeDefs, resolvers, introspection: true, + allowBatchedHttpRequests: true, plugins: [{ requestDidStart (initialRequestContext) { return {