forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {createContext, useContext} from 'react'
2import {QueryClient, useQuery} from '@tanstack/react-query'
3
4import {APP_CONFIG_URL} from '#/env'
5
6const qc = new QueryClient()
7const appConfigQueryKey = ['app-config']
8
9/**
10 * Matches the types defined in our `app-config` worker
11 */
12type AppConfigResponse = {
13 liveNow: {
14 allow: string[]
15 exceptions: {
16 did: string
17 allow: string[]
18 }[]
19 }
20}
21
22export const DEFAULT_APP_CONFIG_RESPONSE: AppConfigResponse = {
23 liveNow: {
24 allow: [],
25 exceptions: [],
26 },
27}
28
29let fetchAppConfigPromise: Promise<AppConfigResponse> | undefined
30
31async function fetchAppConfig(): Promise<AppConfigResponse | null> {
32 try {
33 if (!fetchAppConfigPromise) {
34 fetchAppConfigPromise = (async () => {
35 const r = await fetch(`${APP_CONFIG_URL}/config`)
36 if (!r.ok) throw new Error(await r.text())
37 const data = await r.json()
38 return data
39 })()
40 }
41 return await fetchAppConfigPromise
42 } catch (e) {
43 fetchAppConfigPromise = undefined
44 throw e
45 }
46}
47
48const Context = createContext<AppConfigResponse>(DEFAULT_APP_CONFIG_RESPONSE)
49
50export function Provider({children}: React.PropsWithChildren<{}>) {
51 const {data} = useQuery<AppConfigResponse | null>(
52 {
53 staleTime: Infinity,
54 queryKey: appConfigQueryKey,
55 refetchInterval: query => {
56 // refetch regularly if fetch failed, otherwise never refetch
57 return query.state.status === 'error' ? 60e3 : Infinity
58 },
59 async queryFn() {
60 return fetchAppConfig()
61 },
62 },
63 qc,
64 )
65 return (
66 <Context.Provider value={data ?? DEFAULT_APP_CONFIG_RESPONSE}>
67 {children}
68 </Context.Provider>
69 )
70}
71
72export async function prefetchAppConfig() {
73 try {
74 const data = await fetchAppConfig()
75 if (data) {
76 qc.setQueryData(appConfigQueryKey, data)
77 }
78 } catch {}
79}
80
81export function useAppConfig() {
82 const ctx = useContext(Context)
83 if (!ctx) {
84 throw new Error('useAppConfig must be used within a Provider')
85 }
86 return ctx
87}