forked from beeequeue/yuna
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvue-apollo.ts
132 lines (106 loc) · 3.46 KB
/
vue-apollo.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { ApolloProvider } from "@vue/apollo-option"
import {
createApolloClient,
CreateClientOptions,
} from "vue-cli-plugin-apollo/graphql-client"
import { Store } from "vuex"
import {
defaultDataIdFromObject,
IntrospectionFragmentMatcher,
} from "apollo-cache-inmemory"
import Bottleneck from "bottleneck"
import { captureException } from "@sentry/browser"
import introspectionResult from "@/graphql/generated/introspection-result"
import { createResolvers } from "@/graphql/resolvers"
import { EpisodeListEpisodes, ListEntry } from "@/graphql/generated/types"
import { userStore } from "@/lib/user"
import { getEpisodeCacheKey, isNil, isOfTypename } from "@/utils"
import { getAnilistRequestsUntilLimiting, setAnilistRequests } from "@/state/app"
// Http endpoint
const httpEndpoint = "https://graphql.anilist.co"
const dataIdFromObject = (obj: { __typename?: string; [key: string]: any }) => {
// Episode
if (isOfTypename<EpisodeListEpisodes>(obj, "Episode")) {
return getEpisodeCacheKey(obj)
}
// ListEntry
if (isOfTypename<ListEntry>(obj, "ListEntry")) {
return `ListEntry:${obj.mediaId}`
}
if (obj.__typename) {
if (obj.id !== undefined) {
return `${obj.__typename}:${obj.id}`
}
if (obj._id !== undefined) {
return `${obj.__typename}:${obj._id}`
}
}
return defaultDataIdFromObject(obj)
}
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: introspectionResult,
})
const limiter = new Bottleneck({
reservoir: 85,
reservoirRefreshAmount: 85,
reservoirRefreshInterval: 60 * 1000,
})
const limitedFetch = limiter.wrap(window.fetch)
// Config
const createOptions = (store: Store<any>): CreateClientOptions => ({
// You can use `https` for secure connection (recommended in production)
httpEndpoint,
persisting: false,
ssr: false,
websocketsOnly: false,
wsEndpoint: null,
// Override the way the Authorization header is set
getAuth: () => userStore.get("anilist.token"),
// Fetch override
httpLinkOptions: {
fetch: limitedFetch,
},
// Cache Options
inMemoryCacheOptions: {
dataIdFromObject,
fragmentMatcher,
},
// Client local data
resolvers: createResolvers(store),
})
// Call this in the Vue app file
export const createProvider = (store: Store<any>) => {
// Create apollo client
const { apolloClient, wsClient } = createApolloClient(createOptions(store))
apolloClient.wsClient = wsClient
setInterval(async () => {
const requests = (await limiter.currentReservoir()) || 60
const savedRequests = getAnilistRequestsUntilLimiting(store)
if (requests === savedRequests) return
setAnilistRequests(store, requests)
}, 1000)
// Create vue apollo provider
const apolloProvider = new ApolloProvider({
defaultClient: apolloClient,
defaultOptions: {
$query: {
fetchPolicy: "cache-first",
},
},
async errorHandler({ networkError }) {
if (!isNil(networkError) && (networkError as any)?.statusCode === 429) {
const currentReservoir = (await limiter.currentReservoir()) || 60
await limiter.incrementReservoir(-currentReservoir)
setAnilistRequests(store, (await limiter.currentReservoir()) || 0)
return
}
if (process.env.NODE_ENV === "production") {
if (isNil(networkError)) return
return captureException(networkError)
}
// eslint-disable-next-line no-console
console.error(networkError)
},
})
return apolloProvider
}