forked from HoudiniGraphql/houdini
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhooks.ts
108 lines (84 loc) · 3.11 KB
/
hooks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import type { Cache } from '$houdini/runtime/cache/cache'
import type { DocumentStore, HoudiniClient } from '$houdini/runtime/client'
import configFile from '$houdini/runtime/imports/config'
import type { LRUCache } from '$houdini/runtime/lib/lru'
import type { GraphQLObject, GraphQLVariables, QueryArtifact } from '$houdini/runtime/lib/types'
import { useContext, default as React } from 'react'
import type { SuspenseCache } from './cache'
export type PageComponent = React.ComponentType<{ url: string }>
export type PendingCache = SuspenseCache<
Promise<void> & { resolve: () => void; reject: (message: string) => void }
>
type RouterContext = {
client: HoudiniClient
cache: Cache
// We also need a cache for artifacts so that we can avoid suspending to
// load them if possible.
artifact_cache: SuspenseCache<QueryArtifact>
// We also need a cache for component references so we can avoid suspending
// when we load the same page multiple times
component_cache: SuspenseCache<PageComponent>
// Pages need a way to wait for data
data_cache: SuspenseCache<DocumentStore<GraphQLObject, GraphQLVariables>>
// A way to dedupe requests for a query
ssr_signals: PendingCache
// A way to track the last known good variables
last_variables: LRUCache<GraphQLVariables>
// The current session
session: App.Session
// a function to call that sets the client-side session singletone
setSession: (newSession: Partial<App.Session>) => void
}
export const Context = React.createContext<RouterContext | null>(null)
export const LocationContext = React.createContext<{
pathname: string
params: Record<string, any>
// a function to imperatively navigate to a url
goto: (url: string) => void
}>({
pathname: '',
params: {},
goto: () => {},
})
// export the location information in context
export const useLocation = () => useContext(LocationContext)
export const useRouterContext = () => {
const ctx = React.useContext(Context)
if (!ctx) {
throw new Error('Could not find router context')
}
return ctx
}
export function useClient() {
return useRouterContext().client
}
export function useCache() {
return useRouterContext().cache
}
export function useSession(): [App.Session, (newSession: Partial<App.Session>) => void] {
const ctx = useRouterContext()
// when we update the session we have to do 2 things. (1) we have to update the local state
// that we will use on the client (2) we have to send a request to the server so that it
// can update the cookie that we use for the session
const updateSession = (newSession: Partial<App.Session>) => {
// clear the data cache so that we refetch queries with the new session (will force a cache-lookup)
ctx.data_cache.clear()
// update the local state
ctx.setSession(newSession)
// figure out the url that we will use to send values to the server
const auth = configFile.router?.auth
if (!auth) {
return
}
const url = 'redirect' in auth ? auth.redirect : auth.url
fetch(url, {
method: 'POST',
body: JSON.stringify(newSession),
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
})
}
return [ctx.session, updateSession]
}