remote-content.ts
3.36 KB
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
import { configureStore } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
import { parseHtml } from './html.ts'
interface SiteConfig {
name: string,
baseUrl: string,
}
export const configSlice = createSlice({
name: 'config',
initialState: {
sites: {},
},
reducers: {
setSiteConfig(state, { payload: { name, baseUrl } }) {
if (!state.sites[ name ]) state.sites[ name ] = {}
Object.assign(state.sites[ name ], { baseUrl })
}
},
selectors: {
getSites: (state) => Object.keys(state.sites).filter(site => site !== 'default'),
getSiteBaseUrl: (state, name) => state.sites?.[ name ]?.baseUrl,
},
})
const baseQuery = fetchBaseQuery()
const siteBaseQuery = async (args, api, options) => {
const { site, url } = args
const baseUrl = getSiteBaseUrl(site) || ''
return baseQuery({ ...args, url: `${baseUrl}${url}` }, api, options)
}
export const sitePageSlice = createApi({
reducerPath: 'pages',
tagTypes: ['Site', 'Page'],
keepUnusedDataFor: 60,
refetchOnReconnect: true,
refetchOnMountOrArgChange: true,
baseQuery: siteBaseQuery,
endpoints: builder => ({
getPage: builder.query({
query: (args) => {
const { site, page } = args
return {
site,
url: page,
method: 'GET',
responseHandler: 'text',
}
},
providesTags: (result, err, args) => {
const { site, page } = args
return [
{ type: 'Site', id: site },
{ type: 'Page', id: `${site}:${page}` },
]
},
}),
}),
})
export const store = configureStore({
reducer: {
[ configSlice.reducerPath ]: configSlice.reducer,
[ sitePageSlice.reducerPath ]: sitePageSlice.reducer,
},
middleware: getDefaultMiddleware => getDefaultMiddleware().concat([
sitePageSlice.middleware,
]),
})
export const getUrl = async(url: string) => {
const state = store.getState()
const sites = configSlice.selectors.getSites(state)
for (const site of sites) {
const baseUrl = configSlice.selectors.getSiteBaseUrl(state, site)
if (url.startsWith(baseUrl)) {
return getSitePage(site, url.substring(baseUrl.length))
}
}
return getSitePage('default', url)
}
export const getSitePage = async (site: string, page: string) => {
const result = await store.dispatch(sitePageSlice.endpoints.getPage.initiate({ site, page }))
return result
}
export const setSiteConfig = (siteConfig: SiteConfig) => {
return store.dispatch(configSlice.actions.setSiteConfig(siteConfig))
}
export const getSiteBaseUrl = (name: string): string => {
return configSlice.selectors.getSiteBaseUrl(store.getState(), name)
}
export const clearAll = () => {
return store.dispatch(sitePageSlice.util.invalidateTags([ 'Page' ]))
}
export const clearSite = (site: string) => {
return store.dispatch(sitePageSlice.util.invalidateTags([ { type: 'Site', id: site } ]))
}
export const clearPages = (site: string, ...pages: string) => {
return store.dispatch(sitePageSlice.util.invalidateTags(pages.map(page => ({ type: 'Page', id: `${site}/${page}` }) )))
}
export const prefetch = (site: string, ...pages: string) => {
return Promise.all(pages.map(page => {
return store.dispatch(sitePageSlice.util.prefetch('getPage', { site, page }, { force: true }))
}))
}
setSiteConfig({ name: 'direct' })