diff options
Diffstat (limited to 'src/state/queries')
-rw-r--r-- | src/state/queries/handle-availability.ts | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/state/queries/handle-availability.ts b/src/state/queries/handle-availability.ts new file mode 100644 index 000000000..9391f5d09 --- /dev/null +++ b/src/state/queries/handle-availability.ts @@ -0,0 +1,126 @@ +import {Agent, ComAtprotoTempCheckHandleAvailability} from '@atproto/api' +import {useQuery} from '@tanstack/react-query' + +import { + BSKY_SERVICE, + BSKY_SERVICE_DID, + PUBLIC_BSKY_SERVICE, +} from '#/lib/constants' +import {createFullHandle} from '#/lib/strings/handles' +import {logger} from '#/logger' +import {useDebouncedValue} from '#/components/live/utils' +import * as bsky from '#/types/bsky' + +export const RQKEY_handleAvailability = ( + handle: string, + domain: string, + serviceDid: string, +) => ['handle-availability', {handle, domain, serviceDid}] + +export function useHandleAvailabilityQuery( + { + username, + serviceDomain, + serviceDid, + enabled, + birthDate, + email, + }: { + username: string + serviceDomain: string + serviceDid: string + enabled: boolean + birthDate?: string + email?: string + }, + debounceDelayMs = 500, +) { + const name = username.trim() + const debouncedHandle = useDebouncedValue(name, debounceDelayMs) + + return { + debouncedUsername: debouncedHandle, + enabled: enabled && name === debouncedHandle, + query: useQuery({ + enabled: enabled && name === debouncedHandle, + queryKey: RQKEY_handleAvailability( + debouncedHandle, + serviceDomain, + serviceDid, + ), + queryFn: async () => { + const handle = createFullHandle(name, serviceDomain) + return await checkHandleAvailability(handle, serviceDid, { + email, + birthDate, + typeahead: true, + }) + }, + }), + } +} + +export async function checkHandleAvailability( + handle: string, + serviceDid: string, + { + email, + birthDate, + typeahead, + }: { + email?: string + birthDate?: string + typeahead?: boolean + }, +) { + if (serviceDid === BSKY_SERVICE_DID) { + const agent = new Agent({service: BSKY_SERVICE}) + // entryway has a special API for handle availability + const {data} = await agent.com.atproto.temp.checkHandleAvailability({ + handle, + birthDate, + email, + }) + + if ( + bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultAvailable>( + data.result, + ComAtprotoTempCheckHandleAvailability.isResultAvailable, + ) + ) { + logger.metric('signup:handleAvailable', {typeahead}, {statsig: true}) + + return {available: true} as const + } else if ( + bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultUnavailable>( + data.result, + ComAtprotoTempCheckHandleAvailability.isResultUnavailable, + ) + ) { + logger.metric('signup:handleTaken', {typeahead}, {statsig: true}) + return { + available: false, + suggestions: data.result.suggestions, + } as const + } else { + throw new Error( + `Unexpected result of \`checkHandleAvailability\`: ${JSON.stringify(data.result)}`, + ) + } + } else { + // 3rd party PDSes won't have this API so just try and resolve the handle + const agent = new Agent({service: PUBLIC_BSKY_SERVICE}) + try { + const res = await agent.resolveHandle({ + handle, + }) + + if (res.data.did) { + logger.metric('signup:handleTaken', {typeahead}, {statsig: true}) + return {available: false} as const + } + } catch {} + logger.metric('signup:handleAvailable', {typeahead}, {statsig: true}) + return {available: true} as const + } +} |