forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {ComAtprotoTempCheckHandleAvailability} from '@atproto/api'
2import {useQuery} from '@tanstack/react-query'
3
4import {
5 BSKY_SERVICE,
6 BSKY_SERVICE_DID,
7 PUBLIC_BSKY_SERVICE,
8} from '#/lib/constants'
9import {createFullHandle} from '#/lib/strings/handles'
10import {logger} from '#/logger'
11import {useDebouncedValue} from '#/components/live/utils'
12import * as bsky from '#/types/bsky'
13import {Agent} from '../session/agent'
14
15export const RQKEY_handleAvailability = (
16 handle: string,
17 domain: string,
18 serviceDid: string,
19) => ['handle-availability', {handle, domain, serviceDid}]
20
21export function useHandleAvailabilityQuery(
22 {
23 username,
24 serviceDomain,
25 serviceDid,
26 enabled,
27 birthDate,
28 email,
29 }: {
30 username: string
31 serviceDomain: string
32 serviceDid: string
33 enabled: boolean
34 birthDate?: string
35 email?: string
36 },
37 debounceDelayMs = 500,
38) {
39 const name = username.trim()
40 const debouncedHandle = useDebouncedValue(name, debounceDelayMs)
41
42 return {
43 debouncedUsername: debouncedHandle,
44 enabled: enabled && name === debouncedHandle,
45 query: useQuery({
46 enabled: enabled && name === debouncedHandle,
47 queryKey: RQKEY_handleAvailability(
48 debouncedHandle,
49 serviceDomain,
50 serviceDid,
51 ),
52 queryFn: async () => {
53 const handle = createFullHandle(name, serviceDomain)
54 return await checkHandleAvailability(handle, serviceDid, {
55 email,
56 birthDate,
57 typeahead: true,
58 })
59 },
60 }),
61 }
62}
63
64export async function checkHandleAvailability(
65 handle: string,
66 serviceDid: string,
67 {
68 email,
69 birthDate,
70 typeahead,
71 }: {
72 email?: string
73 birthDate?: string
74 typeahead?: boolean
75 },
76) {
77 if (serviceDid === BSKY_SERVICE_DID) {
78 const agent = new Agent(null, {service: BSKY_SERVICE})
79 // entryway has a special API for handle availability
80 const {data} = await agent.com.atproto.temp.checkHandleAvailability({
81 handle,
82 birthDate,
83 email,
84 })
85
86 if (
87 bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultAvailable>(
88 data.result,
89 ComAtprotoTempCheckHandleAvailability.isResultAvailable,
90 )
91 ) {
92 logger.metric('signup:handleAvailable', {typeahead}, {statsig: true})
93
94 return {available: true} as const
95 } else if (
96 bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultUnavailable>(
97 data.result,
98 ComAtprotoTempCheckHandleAvailability.isResultUnavailable,
99 )
100 ) {
101 logger.metric('signup:handleTaken', {typeahead}, {statsig: true})
102 return {
103 available: false,
104 suggestions: data.result.suggestions,
105 } as const
106 } else {
107 throw new Error(
108 `Unexpected result of \`checkHandleAvailability\`: ${JSON.stringify(data.result)}`,
109 )
110 }
111 } else {
112 // 3rd party PDSes won't have this API so just try and resolve the handle
113 const agent = new Agent(null, {service: PUBLIC_BSKY_SERVICE})
114 try {
115 const res = await agent.resolveHandle({
116 handle,
117 })
118
119 if (res.data.did) {
120 logger.metric('signup:handleTaken', {typeahead}, {statsig: true})
121 return {available: false} as const
122 }
123 } catch {}
124 logger.metric('signup:handleAvailable', {typeahead}, {statsig: true})
125 return {available: true} as const
126 }
127}