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 {useDebouncedValue} from '#/components/live/utils'
11import {useAnalytics} from '#/analytics'
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 ax = useAnalytics()
40 const name = username.trim()
41 const debouncedHandle = useDebouncedValue(name, debounceDelayMs)
42
43 return {
44 debouncedUsername: debouncedHandle,
45 enabled: enabled && name === debouncedHandle,
46 query: useQuery({
47 enabled: enabled && name === debouncedHandle,
48 queryKey: RQKEY_handleAvailability(
49 debouncedHandle,
50 serviceDomain,
51 serviceDid,
52 ),
53 queryFn: async () => {
54 const handle = createFullHandle(name, serviceDomain)
55 const res = await checkHandleAvailability(handle, serviceDid, {
56 email,
57 birthDate,
58 })
59 if (res.available) {
60 ax.metric('signup:handleAvailable', {typeahead: true})
61 } else {
62 ax.metric('signup:handleTaken', {typeahead: true})
63 }
64 return res
65 },
66 }),
67 }
68}
69
70export async function checkHandleAvailability(
71 handle: string,
72 serviceDid: string,
73 {
74 email,
75 birthDate,
76 }: {
77 email?: string
78 birthDate?: string
79 },
80) {
81 if (serviceDid === BSKY_SERVICE_DID) {
82 const agent = new Agent(null, {service: BSKY_SERVICE})
83 // entryway has a special API for handle availability
84 const {data} = await agent.com.atproto.temp.checkHandleAvailability({
85 handle,
86 birthDate,
87 email,
88 })
89
90 if (
91 bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultAvailable>(
92 data.result,
93 ComAtprotoTempCheckHandleAvailability.isResultAvailable,
94 )
95 ) {
96 return {available: true} as const
97 } else if (
98 bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultUnavailable>(
99 data.result,
100 ComAtprotoTempCheckHandleAvailability.isResultUnavailable,
101 )
102 ) {
103 return {
104 available: false,
105 suggestions: data.result.suggestions,
106 } as const
107 } else {
108 throw new Error(
109 `Unexpected result of \`checkHandleAvailability\`: ${JSON.stringify(data.result)}`,
110 )
111 }
112 } else {
113 // 3rd party PDSes won't have this API so just try and resolve the handle
114 const agent = new Agent(null, {service: PUBLIC_BSKY_SERVICE})
115 try {
116 const res = await agent.resolveHandle({
117 handle,
118 })
119
120 if (res.data.did) {
121 return {available: false} as const
122 }
123 } catch {}
124 return {available: true} as const
125 }
126}