@data-fair/lib-vue 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/session.d.ts +12 -0
- package/session.js +53 -13
package/package.json
CHANGED
package/session.d.ts
CHANGED
|
@@ -17,6 +17,14 @@ export interface SessionOptions {
|
|
|
17
17
|
req?: IncomingMessage;
|
|
18
18
|
cookies?: GenericCookies;
|
|
19
19
|
customFetch?: typeof fetch;
|
|
20
|
+
siteInfo?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface Theme {
|
|
23
|
+
primaryColor: string;
|
|
24
|
+
}
|
|
25
|
+
export interface SiteInfo {
|
|
26
|
+
theme: Theme;
|
|
27
|
+
logo?: string;
|
|
20
28
|
}
|
|
21
29
|
export interface Session {
|
|
22
30
|
state: SessionState;
|
|
@@ -26,6 +34,7 @@ export interface Session {
|
|
|
26
34
|
accountRole: ComputedRef<SessionState['accountRole']>;
|
|
27
35
|
lang: ComputedRef<SessionState['lang']>;
|
|
28
36
|
dark: ComputedRef<SessionState['dark']>;
|
|
37
|
+
site: Ref<SiteInfo | null>;
|
|
29
38
|
loginUrl: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => string;
|
|
30
39
|
login: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => void;
|
|
31
40
|
logout: (redirect?: string) => Promise<void>;
|
|
@@ -34,6 +43,7 @@ export interface Session {
|
|
|
34
43
|
asAdmin: (user: any | null) => Promise<void>;
|
|
35
44
|
cancelDeletion: () => Promise<void>;
|
|
36
45
|
keepalive: () => Promise<void>;
|
|
46
|
+
refreshSiteInfo: () => Promise<void>;
|
|
37
47
|
switchDark: (value: boolean) => void;
|
|
38
48
|
switchLang: (value: string) => void;
|
|
39
49
|
topLocation: Ref<Location | undefined>;
|
|
@@ -56,6 +66,7 @@ export declare function createSession(initOptions: Partial<SessionOptions>): Pro
|
|
|
56
66
|
accountRole: ComputedRef<SessionState["accountRole"]>;
|
|
57
67
|
lang: ComputedRef<SessionState["lang"]>;
|
|
58
68
|
dark: ComputedRef<SessionState["dark"]>;
|
|
69
|
+
site: Ref<SiteInfo | null>;
|
|
59
70
|
loginUrl: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => string;
|
|
60
71
|
login: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => void;
|
|
61
72
|
logout: (redirect?: string) => Promise<void>;
|
|
@@ -64,6 +75,7 @@ export declare function createSession(initOptions: Partial<SessionOptions>): Pro
|
|
|
64
75
|
asAdmin: (user: any | null) => Promise<void>;
|
|
65
76
|
cancelDeletion: () => Promise<void>;
|
|
66
77
|
keepalive: () => Promise<void>;
|
|
78
|
+
refreshSiteInfo: () => Promise<void>;
|
|
67
79
|
switchDark: (value: boolean) => void;
|
|
68
80
|
switchLang: (value: string) => void;
|
|
69
81
|
topLocation: Ref<Location | undefined>;
|
package/session.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { reactive, computed, watch, inject } from 'vue'
|
|
1
|
+
import { reactive, computed, watch, inject, ref } from 'vue'
|
|
2
2
|
import { ofetch } from 'ofetch'
|
|
3
3
|
import { jwtDecode } from 'jwt-decode'
|
|
4
4
|
import cookiesModule from 'universal-cookie'
|
|
@@ -55,9 +55,10 @@ export async function getSession (initOptions) {
|
|
|
55
55
|
})
|
|
56
56
|
// the core state of the session that is filled by reading cookies
|
|
57
57
|
const state = reactive({})
|
|
58
|
+
const site = ref(null)
|
|
58
59
|
// cookies are the source of truth and this information is transformed into the state reactive object
|
|
59
60
|
const cookies = initOptions?.cookies ?? new Cookies(options.req?.headers.cookie)
|
|
60
|
-
const
|
|
61
|
+
const readState = () => {
|
|
61
62
|
const darkCookie = cookies.get('theme_dark')
|
|
62
63
|
state.dark = darkCookie === '1' || darkCookie === 'true'
|
|
63
64
|
const langCookie = cookies.get('i18n_lang')
|
|
@@ -107,16 +108,22 @@ export async function getSession (initOptions) {
|
|
|
107
108
|
}
|
|
108
109
|
state.accountRole = 'admin'
|
|
109
110
|
}
|
|
111
|
+
if (!ssr) {
|
|
112
|
+
const siteInfoStorage = getSiteInfoStorage()
|
|
113
|
+
site.value = siteInfoStorage ? siteInfoStorage.info : null
|
|
114
|
+
}
|
|
110
115
|
}
|
|
111
|
-
|
|
116
|
+
readState()
|
|
112
117
|
debug('initial state', state)
|
|
113
118
|
if (!ssr) {
|
|
114
119
|
// sessionData is also stored in localStorage as a way to access it in simpler pages that do not require use-session
|
|
115
120
|
// and in order to listen to storage event from other contexts and sync session info accross windows and tabs
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
if (!ssr) {
|
|
122
|
+
const storageListener = (event) => {
|
|
123
|
+
if (event.key === 'sd-session' + options.sitePath) { readState() }
|
|
124
|
+
}
|
|
125
|
+
window.addEventListener('storage', storageListener)
|
|
118
126
|
}
|
|
119
|
-
window.addEventListener('storage', storageListener)
|
|
120
127
|
// we cannot use onUnmounted here or we get warnings "onUnmounted is called when there is no active component instance to be associated with. "
|
|
121
128
|
// TODO: should we have another cleanup mechanism ?
|
|
122
129
|
// onUnmounted(() => { window.removeEventListener('storage', storageListener) })
|
|
@@ -166,7 +173,7 @@ export async function getSession (initOptions) {
|
|
|
166
173
|
const switchOrganization = (org, dep) => {
|
|
167
174
|
if (org) { cookies.set('id_token_org', org, { path: cookiesPath }) } else { cookies.remove('id_token_org') }
|
|
168
175
|
if (dep) { cookies.set('id_token_dep', dep, { path: cookiesPath }) } else { cookies.remove('id_token_dep') }
|
|
169
|
-
|
|
176
|
+
readState()
|
|
170
177
|
}
|
|
171
178
|
const setAdminMode = async (adminMode, redirect) => {
|
|
172
179
|
if (adminMode) {
|
|
@@ -185,36 +192,67 @@ export async function getSession (initOptions) {
|
|
|
185
192
|
} else {
|
|
186
193
|
await customFetch(`${options.directoryUrl}/api/auth/asadmin`, { method: 'DELETE' })
|
|
187
194
|
}
|
|
188
|
-
|
|
195
|
+
readState()
|
|
189
196
|
}
|
|
190
197
|
const cancelDeletion = async () => {
|
|
191
198
|
if (state.user == null) { return }
|
|
192
199
|
await customFetch(`${options.directoryUrl}/api/users/${state.user.id}`, { method: 'PATCH', body: ({ plannedDeletion: null }) })
|
|
193
|
-
|
|
200
|
+
readState()
|
|
194
201
|
}
|
|
195
202
|
const switchDark = (value) => {
|
|
196
203
|
const maxAge = 60 * 60 * 24 * 365 // 1 year
|
|
197
204
|
cookies.set('theme_dark', `${value}`, { maxAge, path: cookiesPath })
|
|
198
|
-
|
|
205
|
+
readState()
|
|
199
206
|
}
|
|
200
207
|
const switchLang = (value) => {
|
|
201
208
|
const maxAge = 60 * 60 * 24 * 365 // 1 year
|
|
202
209
|
cookies.set('i18n_lang', value, { maxAge, path: cookiesPath })
|
|
203
|
-
|
|
210
|
+
readState()
|
|
204
211
|
}
|
|
205
212
|
const keepalive = async () => {
|
|
206
213
|
if (state.user == null) { return }
|
|
207
|
-
|
|
214
|
+
if (!ssr) {
|
|
215
|
+
window.localStorage.setItem('sd-keepalive' + options.sitePath, `${new Date().getTime()}`)
|
|
216
|
+
}
|
|
208
217
|
await customFetch(`${options.directoryUrl}/api/auth/keepalive`, { method: 'POST' })
|
|
209
|
-
|
|
218
|
+
readState()
|
|
219
|
+
}
|
|
220
|
+
const getSiteInfoStorage = () => {
|
|
221
|
+
const siteInfoStorageStr = window.localStorage.getItem('sd-site-info' + options.sitePath)
|
|
222
|
+
return siteInfoStorageStr ? JSON.parse(siteInfoStorageStr) : null
|
|
223
|
+
}
|
|
224
|
+
const setSiteInfoStorage = (siteInfo) => {
|
|
225
|
+
const siteInfoStorage = { info: siteInfo, updatedAt: new Date().getTime() }
|
|
226
|
+
window.localStorage.setItem('sd-site-info' + options.sitePath, JSON.stringify(siteInfoStorage))
|
|
227
|
+
}
|
|
228
|
+
const refreshSiteInfo = async () => {
|
|
229
|
+
const siteInfo = await customFetch(`${options.directoryUrl}/api/sites/_public`) ?? null
|
|
230
|
+
site.value = siteInfo
|
|
231
|
+
if (!ssr) {
|
|
232
|
+
setSiteInfoStorage(siteInfo)
|
|
233
|
+
}
|
|
210
234
|
}
|
|
211
235
|
// immediately performs a keepalive, but only on top windows (not iframes or popups)
|
|
212
236
|
// and only if it was not done very recently (maybe from a refreshed page next to this one)
|
|
237
|
+
// also run an auto-refresh loop
|
|
213
238
|
if (!ssr && window.top === window.self) {
|
|
214
239
|
const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)
|
|
215
240
|
if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > 10000) {
|
|
216
241
|
await keepalive()
|
|
217
242
|
}
|
|
243
|
+
if (options.siteInfo) {
|
|
244
|
+
const lastSiteInfoStorage = getSiteInfoStorage()
|
|
245
|
+
if (!lastSiteInfoStorage || (new Date().getTime() - Number(lastSiteInfoStorage.updatedAt)) > 10000) {
|
|
246
|
+
await refreshSiteInfo()
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const refreshLoopDelay = 10 * 60 * 1000 // 10 minutes
|
|
250
|
+
setInterval(() => {
|
|
251
|
+
const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)
|
|
252
|
+
if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > refreshLoopDelay / 2) {
|
|
253
|
+
keepalive().catch(err => console.error(err))
|
|
254
|
+
}
|
|
255
|
+
}, refreshLoopDelay)
|
|
218
256
|
}
|
|
219
257
|
const session = {
|
|
220
258
|
state,
|
|
@@ -224,6 +262,7 @@ export async function getSession (initOptions) {
|
|
|
224
262
|
accountRole: computed(() => state.accountRole),
|
|
225
263
|
dark: computed(() => state.dark),
|
|
226
264
|
lang: computed(() => state.lang),
|
|
265
|
+
site,
|
|
227
266
|
loginUrl,
|
|
228
267
|
login,
|
|
229
268
|
logout,
|
|
@@ -232,6 +271,7 @@ export async function getSession (initOptions) {
|
|
|
232
271
|
asAdmin,
|
|
233
272
|
cancelDeletion,
|
|
234
273
|
keepalive,
|
|
274
|
+
refreshSiteInfo,
|
|
235
275
|
switchDark,
|
|
236
276
|
switchLang,
|
|
237
277
|
topLocation,
|