@data-fair/lib-vue 1.28.1 → 1.29.1
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 +20 -5
- package/session.js +52 -13
- package/session.js.map +1 -1
package/package.json
CHANGED
package/session.d.ts
CHANGED
|
@@ -44,16 +44,16 @@ export interface Colors {
|
|
|
44
44
|
admin: string;
|
|
45
45
|
'on-admin': string;
|
|
46
46
|
}
|
|
47
|
-
interface FullSiteInfo {
|
|
47
|
+
export interface FullSiteInfo {
|
|
48
48
|
main?: boolean;
|
|
49
49
|
theme: {
|
|
50
50
|
logo?: string;
|
|
51
51
|
colors: Colors;
|
|
52
|
-
dark
|
|
52
|
+
dark?: boolean;
|
|
53
53
|
darkColors?: Colors;
|
|
54
|
-
hc
|
|
54
|
+
hc?: boolean;
|
|
55
55
|
hcColors?: Colors;
|
|
56
|
-
hcDark
|
|
56
|
+
hcDark?: boolean;
|
|
57
57
|
hcDarkColors?: Colors;
|
|
58
58
|
};
|
|
59
59
|
}
|
|
@@ -67,7 +67,8 @@ export interface SiteInfo {
|
|
|
67
67
|
colors: Colors;
|
|
68
68
|
owner: AccountKeys;
|
|
69
69
|
}
|
|
70
|
-
type
|
|
70
|
+
export type AppliedTheme = 'default' | 'dark' | 'hc' | 'hc-dark';
|
|
71
|
+
export type Theme = AppliedTheme | 'system';
|
|
71
72
|
export interface Session {
|
|
72
73
|
state: SessionState;
|
|
73
74
|
user: ComputedRef<SessionState['user']>;
|
|
@@ -99,6 +100,20 @@ export type SessionAuthenticated = Omit<Session, 'state' | 'user' | 'account' |
|
|
|
99
100
|
account: ComputedRef<SessionStateAuthenticated['account']>;
|
|
100
101
|
accountRole: ComputedRef<SessionStateAuthenticated['accountRole']>;
|
|
101
102
|
};
|
|
103
|
+
export type ThemeOffers = {
|
|
104
|
+
theme: {
|
|
105
|
+
dark?: boolean;
|
|
106
|
+
hc?: boolean;
|
|
107
|
+
hcDark?: boolean;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Resolves a user theme preference to a concrete AppliedTheme — returns the explicit choice when set,
|
|
112
|
+
* otherwise picks the best variant offered by `site` based on the OS `prefers-color-scheme` / `forced-colors`
|
|
113
|
+
* media queries. Always call this before handing a theme name to Vuetify: its built-in `'system'` defaultTheme
|
|
114
|
+
* bypasses custom themes and falls back to its own light/dark.
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveTheme(userTheme: Theme | null, site: ThemeOffers): AppliedTheme;
|
|
102
117
|
export declare function getSession(initOptions: Partial<SessionOptions>): Promise<Session>;
|
|
103
118
|
export declare const sessionKey: unique symbol;
|
|
104
119
|
export declare function createSession(initOptions: Partial<SessionOptions>): Promise<{
|
package/session.js
CHANGED
|
@@ -10,10 +10,26 @@ export * from '@data-fair/lib-common-types/session/index.js';
|
|
|
10
10
|
const Cookies = cookiesModule;
|
|
11
11
|
const debug = Debug('session');
|
|
12
12
|
debug.log = console.log.bind(console);
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Resolves a user theme preference to a concrete AppliedTheme — returns the explicit choice when set,
|
|
15
|
+
* otherwise picks the best variant offered by `site` based on the OS `prefers-color-scheme` / `forced-colors`
|
|
16
|
+
* media queries. Always call this before handing a theme name to Vuetify: its built-in `'system'` defaultTheme
|
|
17
|
+
* bypasses custom themes and falls back to its own light/dark.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveTheme(userTheme, site) {
|
|
20
|
+
// honor an explicit choice only while `site` still offers it; otherwise fall through to
|
|
21
|
+
// the OS-preference resolution below (a theme disabled after selection must not stick)
|
|
22
|
+
if (userTheme === 'default')
|
|
23
|
+
return 'default';
|
|
24
|
+
if (userTheme === 'dark' && site.theme.dark)
|
|
25
|
+
return 'dark';
|
|
26
|
+
if (userTheme === 'hc' && site.theme.hc)
|
|
27
|
+
return 'hc';
|
|
28
|
+
if (userTheme === 'hc-dark' && site.theme.hcDark)
|
|
29
|
+
return 'hc-dark';
|
|
14
30
|
// see https://www.scottohara.me/blog/2021/10/01/detect-high-contrast-and-dark-modes.html
|
|
15
|
-
const preferDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
16
|
-
const preferHC = window.matchMedia && window.matchMedia('(forced-colors: active)').matches;
|
|
31
|
+
const preferDark = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
32
|
+
const preferHC = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(forced-colors: active)').matches;
|
|
17
33
|
if (site.theme.hcDark && preferDark && preferHC)
|
|
18
34
|
return 'hc-dark';
|
|
19
35
|
if (site.theme.hc && preferHC)
|
|
@@ -84,7 +100,9 @@ export async function getSession(initOptions) {
|
|
|
84
100
|
// cookies are the source of truth and this information is transformed into the state reactive object
|
|
85
101
|
const cookies = initOptions?.cookies ?? new Cookies(options.req?.headers.cookie);
|
|
86
102
|
const readState = () => {
|
|
87
|
-
|
|
103
|
+
// absent cookie is treated as implicit 'system' so consumers (theme-switcher
|
|
104
|
+
// radios, host plugins) always have a meaningful value to bind to.
|
|
105
|
+
theme.value = cookies.get('theme') ?? 'system';
|
|
88
106
|
const langCookie = cookies.get('i18n_lang');
|
|
89
107
|
state.lang = langCookie ?? options.defaultLang;
|
|
90
108
|
const idToken = cookies.get('id_token');
|
|
@@ -198,14 +216,20 @@ export async function getSession(initOptions) {
|
|
|
198
216
|
goTo(loginUrl(redirect, extraParams, immediateRedirect));
|
|
199
217
|
};
|
|
200
218
|
const logout = async (redirect) => {
|
|
201
|
-
await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' });
|
|
219
|
+
const response = await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' });
|
|
202
220
|
// sometimes server side cookie deletion is not applied immediately in browser local js context
|
|
203
221
|
// so we do it here to
|
|
204
222
|
cookies.remove('id_token');
|
|
205
223
|
cookies.remove('id_token_org');
|
|
206
224
|
cookies.remove('id_token_dep');
|
|
207
225
|
cookies.remove('id_token_role');
|
|
208
|
-
|
|
226
|
+
// RP-Initiated Logout: if the server returned an endSessionUrl, redirect to the SSO logout
|
|
227
|
+
if (response?.endSessionUrl) {
|
|
228
|
+
goTo(response.endSessionUrl);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
goTo(redirect ?? options.logoutRedirectUrl ?? null);
|
|
232
|
+
}
|
|
209
233
|
};
|
|
210
234
|
const switchOrganization = (org, dep, role, updateState = true) => {
|
|
211
235
|
const cookieOpts = { path: cookiesPath };
|
|
@@ -264,8 +288,14 @@ export async function getSession(initOptions) {
|
|
|
264
288
|
goTo(null);
|
|
265
289
|
};
|
|
266
290
|
const switchTheme = (value) => {
|
|
267
|
-
|
|
268
|
-
|
|
291
|
+
// an absent cookie already means 'system' (see init above), so don't persist it explicitly
|
|
292
|
+
if (value === 'system') {
|
|
293
|
+
cookies.remove('theme', { path: cookiesPath });
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const maxAge = 60 * 60 * 24 * 365; // 1 year
|
|
297
|
+
cookies.set('theme', value, { maxAge, path: cookiesPath });
|
|
298
|
+
}
|
|
269
299
|
goTo(null);
|
|
270
300
|
};
|
|
271
301
|
const keepalive = async () => {
|
|
@@ -306,15 +336,14 @@ export async function getSession(initOptions) {
|
|
|
306
336
|
authOnlyOtherSite: siteInfo.authOnlyOtherSite,
|
|
307
337
|
owner: siteInfo.owner
|
|
308
338
|
};
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (theme.value === 'hc')
|
|
339
|
+
const applied = resolveTheme(theme.value, siteInfo);
|
|
340
|
+
if (applied === 'hc')
|
|
312
341
|
partialSite.colors = siteInfo.theme.hcColors;
|
|
313
|
-
if (
|
|
342
|
+
if (applied === 'dark') {
|
|
314
343
|
partialSite.colors = siteInfo.theme.darkColors;
|
|
315
344
|
partialSite.dark = true;
|
|
316
345
|
}
|
|
317
|
-
if (
|
|
346
|
+
if (applied === 'hc-dark') {
|
|
318
347
|
partialSite.colors = siteInfo.theme.hcDarkColors;
|
|
319
348
|
partialSite.dark = true;
|
|
320
349
|
}
|
|
@@ -329,6 +358,16 @@ export async function getSession(initOptions) {
|
|
|
329
358
|
// @ts-ignore
|
|
330
359
|
if (!ssr && window.__PUBLIC_SITE_INFO)
|
|
331
360
|
setSiteInfo(window.__PUBLIC_SITE_INFO);
|
|
361
|
+
// re-apply the theme when the OS preference changes while the user is on
|
|
362
|
+
// 'system'. Important for mobile devices that switch light/dark over the day.
|
|
363
|
+
if (!ssr && typeof window !== 'undefined' && window.matchMedia) {
|
|
364
|
+
const onOsPrefChange = () => {
|
|
365
|
+
if (theme.value === 'system' && fullSite.value)
|
|
366
|
+
setSiteInfo(fullSite.value);
|
|
367
|
+
};
|
|
368
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', onOsPrefChange);
|
|
369
|
+
window.matchMedia('(forced-colors: active)').addEventListener('change', onOsPrefChange);
|
|
370
|
+
}
|
|
332
371
|
// immediately performs a keepalive, but only on top windows (not iframes or popups)
|
|
333
372
|
// and only if it was not done very recently (maybe from a refreshed page next to this one)
|
|
334
373
|
// also run an auto-refresh loop
|
package/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["session.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IncomingMessage } from 'node:http'\nimport { type Ref, type ComputedRef, type App, shallowReadonly } from 'vue'\nimport { FetchError, type fetch } from 'ofetch'\n\n// minimal structural type compatible with both vue-router v4 and v5\ninterface RouteLocationLike { fullPath: string }\nimport { type AccountKeys, type SessionState, type SessionStateAuthenticated, type User } from '@data-fair/lib-common-types/session/index.js'\nimport { reactive, computed, watch, inject, ref, shallowRef, readonly } from 'vue'\nimport { ofetch } from 'ofetch'\nimport { jwtDecode } from 'jwt-decode'\nimport cookiesModule from 'universal-cookie'\nimport Debug from 'debug'\nimport inIframe from '@data-fair/lib-utils/in-iframe.js'\n\nexport * from '@data-fair/lib-common-types/session/index.js'\n\nconst Cookies = cookiesModule as unknown as typeof cookiesModule.default\n\ninterface GenericCookies {\n get: (key: string) => string | undefined\n set: (key: string, value: string, options?: Record<string, any>) => void\n remove: (key: string) => void\n}\n\nexport interface SessionOptions {\n sitePath: string\n directoryUrl: string\n defaultLang: string\n route?: RouteLocationLike\n logoutRedirectUrl?: string\n req?: IncomingMessage\n cookies?: GenericCookies\n customFetch?: typeof fetch\n siteInfo?: boolean\n}\n\nexport interface Colors {\n background: string\n 'on-background': string\n surface: string\n 'on-surface': string\n primary: string\n 'on-primary': string\n 'text-primary': string\n secondary: string\n 'on-secondary': string\n 'text-secondary': string\n error: string\n 'on-error': string\n info: string\n 'on-info': string\n success: string\n 'on-success': string\n warning: string\n 'on-warning': string\n admin: string\n 'on-admin': string\n}\n\ninterface FullSiteInfo {\n main?: boolean\n theme: {\n logo?: string\n colors: Colors\n dark: boolean\n darkColors?: Colors\n hc: boolean\n hcColors?: Colors\n hcDark: boolean\n hcDarkColors?: Colors\n }\n}\n\nexport interface SiteInfo {\n main?: boolean\n isAccountMain?: boolean\n authMode: string\n authOnlyOtherSite?: string\n logo?: string\n dark?: boolean\n colors: Colors\n owner: AccountKeys\n}\n\ntype Theme = 'default' | 'dark' | 'hc' | 'hc-dark'\n\nexport interface Session {\n state: SessionState\n user: ComputedRef<SessionState['user']>\n organization: ComputedRef<SessionState['organization']>\n account: ComputedRef<SessionState['account']>\n accountRole: ComputedRef<SessionState['accountRole']>\n siteRole: ComputedRef<SessionState['siteRole']>\n lang: ComputedRef<SessionState['lang']>\n theme: Ref<null | Theme>\n site: Ref<SiteInfo | null>\n fullSite: Ref<FullSiteInfo | null>\n loginUrl: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => string\n login: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => void\n logout: (redirect?: string) => Promise<void>\n switchOrganization: (org: string | null, dep?: string, role?: string, updateState?: boolean) => void\n setAdminMode: (adminMode: boolean, redirect?: string) => Promise<void>\n asAdmin: (user: any | null) => Promise<void>\n cancelDeletion: () => Promise<void>\n keepalive: () => Promise<void>\n refreshSiteInfo: () => Promise<void>\n switchTheme: (value: Theme) => void\n switchLang: (value: string) => void\n topLocation: Ref<Location | undefined>\n options: SessionOptions\n}\n\nexport type SessionAuthenticated = Omit<Session, 'state' | 'user' | 'account' | 'accountRole'> & {\n state: SessionStateAuthenticated\n user: ComputedRef<SessionStateAuthenticated['user']>\n account: ComputedRef<SessionStateAuthenticated['account']>\n accountRole: ComputedRef<SessionStateAuthenticated['accountRole']>\n}\n\nconst debug = Debug('session')\ndebug.log = console.log.bind(console)\n\nfunction getDefaultTheme (site: FullSiteInfo): Theme {\n // see https://www.scottohara.me/blog/2021/10/01/detect-high-contrast-and-dark-modes.html\n const preferDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches\n const preferHC = window.matchMedia && window.matchMedia('(forced-colors: active)').matches\n if (site.theme.hcDark && preferDark && preferHC) return 'hc-dark'\n if (site.theme.hc && preferHC) return 'hc'\n if (site.theme.dark && preferDark) return 'dark'\n return 'default'\n}\n\nfunction jwtDecodeAlive (jwt: string | null): User | undefined {\n if (!jwt) return\n const decoded = jwtDecode(jwt) as any\n if (!decoded) return\n const now = Math.ceil(Date.now().valueOf() / 1000)\n if (typeof decoded.exp !== 'undefined' && decoded.exp < now) {\n // token expired\n return\n }\n if (typeof decoded.nbf !== 'undefined' && decoded.nbf > now) {\n console.warn(`token not yet valid: ${decoded.nbf}>${now}, ${JSON.stringify(decoded)}`)\n // do not return here, this is probably a false flag due to a slightly mismatched clock\n }\n return decoded as User\n}\n\nconst getTopLocation = () => {\n try {\n return window.top ? window.top.location : window.location\n } catch (err) {\n return window.location\n }\n}\n\nconst goTo = (url: string | null) => {\n const topLocation = getTopLocation()\n if (topLocation == null) {\n throw new TypeError('session.goTo was called without access to the window object or its location')\n }\n if (url) topLocation.href = url\n else topLocation.reload()\n}\n\nconst defaultOptions = { directoryUrl: '/simple-directory', sitePath: '', defaultLang: 'fr' }\n\nexport async function getSession (initOptions: Partial<SessionOptions>): Promise<Session> {\n const options = { ...defaultOptions, ...initOptions }\n const cookiesPath = options.sitePath + '/'\n debug(`init directoryUrl=${options.directoryUrl}, cookiesPath=${cookiesPath}`)\n const ssr = !!options.req\n if (ssr) debug('run in SSR context')\n\n const customFetch = initOptions?.customFetch ?? ofetch\n\n // use vue-router to detect page change and maintain a reference to the current page location\n // top page if we are in iframe context\n const topLocation = computed(() => {\n if (ssr) return undefined\n\n if (options.route?.fullPath) { /* empty */ } // adds reactivity\n const location = getTopLocation()\n debug('update location based on route change', location)\n return location\n })\n\n // the core state of the session that is filled by reading cookies\n const state = reactive({} as SessionState)\n const fullSite = shallowRef<FullSiteInfo | null>(null)\n const site = shallowRef<SiteInfo | null>(null)\n const theme = ref<Theme | null>(null)\n\n // cookies are the source of truth and this information is transformed into the state reactive object\n const cookies = initOptions?.cookies ?? new Cookies(options.req?.headers.cookie)\n const readState = () => {\n theme.value = cookies.get('theme') ?? null\n\n const langCookie = cookies.get('i18n_lang')\n state.lang = langCookie ?? options.defaultLang\n\n const idToken = cookies.get('id_token')\n const user = jwtDecodeAlive(idToken)\n\n if (!user) {\n delete state.user\n delete state.organization\n delete state.account\n delete state.accountRole\n return\n }\n\n // this is to prevent null values that are put by SD versions that do not strictly respect their schema\n for (const org of user.organizations) {\n if (!org.department) {\n delete org.department\n delete org.departmentName\n }\n }\n\n state.user = user\n const organizationId = cookies.get('id_token_org')\n const departmentId = cookies.get('id_token_dep')\n const switchedRole = cookies.get('id_token_role')\n if (organizationId) {\n state.organization = state.user.organizations.find(o => {\n if (o.id !== organizationId) return false\n if (departmentId && departmentId !== o.department) return false\n if (switchedRole && switchedRole !== o.role) return false\n return true\n })\n } else {\n delete state.organization\n }\n if (state.organization) {\n state.account = {\n type: 'organization',\n id: state.organization.id,\n name: state.organization.name,\n department: state.organization.department,\n departmentName: state.organization.departmentName\n }\n state.accountRole = state.organization.role\n } else {\n state.account = {\n type: 'user',\n id: state.user.id,\n name: state.user.name\n }\n state.accountRole = 'admin'\n }\n\n if (state.user?.siteOwner) {\n if (state.user.siteOwner.type === 'user' && state.user.siteOwner.id === state.user.id) {\n state.siteRole = 'admin'\n }\n if (state.user.siteOwner.type === 'organization' && state.user.siteOwner.id === state.organization?.id) {\n state.siteRole = state.organization.role\n }\n }\n }\n readState()\n debug('initial state', state)\n\n if (!ssr) {\n // sessionData is also stored in localStorage as a way to access it in simpler pages that do not require use-session\n // and in order to listen to storage event from other contexts and sync session info accross windows and tabs\n const storageListener = (event: StorageEvent) => {\n if (event.key === 'sd-session' + options.sitePath) readState()\n }\n window.addEventListener('storage', storageListener)\n\n // we cannot use onUnmounted here or we get warnings \"onUnmounted is called when there is no active component instance to be associated with. \"\n // TODO: should we have another cleanup mechanism ?\n // onUnmounted(() => { window.removeEventListener('storage', storageListener) })\n\n // trigger some full page refresh when some key session elements are changed\n // the danger of simply using reactivity is too high, data must be re-fetched, etc.\n watch(() => state.account, (account, oldAccount) => {\n if (account?.type !== oldAccount?.type || account?.id !== oldAccount?.id || account?.department !== oldAccount?.department) {\n goTo(null)\n }\n })\n watch(() => state.lang, () => {\n goTo(null)\n })\n watch(() => state.dark, () => {\n goTo(null)\n })\n watch(state, (state) => {\n if (!ssr) {\n window.localStorage.setItem('sd-session' + options.sitePath, JSON.stringify(state))\n }\n debug('state changed', state)\n })\n }\n\n // login can be performed as a simple link (please use target=top) or as a function\n function loginUrl (redirect?: string, extraParams: Record<string, string> = {}, immediateRedirect = true): string {\n // login can also be used to redirect user immediately if he is already logged\n if (redirect && state.user && immediateRedirect) return redirect\n if (!redirect && topLocation.value) redirect = topLocation.value.href\n let url = `${options.directoryUrl}/login?redirect=${encodeURIComponent(redirect ?? '')}`\n Object.keys(extraParams).filter(key => ![null, undefined, ''].includes(extraParams[key])).forEach((key) => {\n url += `&${key}=${encodeURIComponent(extraParams[key])}`\n })\n return url\n }\n const login = (redirect?: string, extraParams: Record<string, string> = {}, immediateRedirect = true) => {\n goTo(loginUrl(redirect, extraParams, immediateRedirect))\n }\n const logout = async (redirect?: string) => {\n await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' })\n // sometimes server side cookie deletion is not applied immediately in browser local js context\n // so we do it here to\n cookies.remove('id_token')\n cookies.remove('id_token_org')\n cookies.remove('id_token_dep')\n cookies.remove('id_token_role')\n goTo(redirect ?? options.logoutRedirectUrl ?? null)\n }\n\n const switchOrganization = (org: string | null, dep?: string, role?: string, updateState = true) => {\n const cookieOpts = { path: cookiesPath }\n if (org) cookies.set('id_token_org', org, cookieOpts)\n else cookies.remove('id_token_org', cookieOpts)\n if (dep) cookies.set('id_token_dep', dep, cookieOpts)\n else cookies.remove('id_token_dep', cookieOpts)\n if (role) cookies.set('id_token_role', role, cookieOpts)\n else cookies.remove('id_token_role', cookieOpts)\n if (updateState) readState()\n }\n\n const setAdminMode = async (adminMode: boolean, redirect?: string) => {\n if (adminMode) {\n const params: Record<string, string> = { adminMode: 'true' }\n if (state.user != null) params.email = state.user.email\n // preserve current active org/dep\n if (state.organization) {\n params.org = state.organization.id\n if (state.organization.department) params.dep = state.organization.department\n }\n const url = loginUrl(redirect, params, true)\n goTo(url)\n } else {\n await customFetch(`${options.directoryUrl}/api/auth/adminmode`, { method: 'DELETE' })\n goTo(redirect ?? null)\n }\n }\n\n const asAdmin = async (user: any | null) => {\n if (user) {\n await customFetch(`${options.directoryUrl}/api/auth/asadmin`, { method: 'POST', body: user })\n } else {\n await customFetch(`${options.directoryUrl}/api/auth/asadmin`, { method: 'DELETE' })\n }\n goTo(null)\n }\n\n const cancelDeletion = async () => {\n if (state.user == null) return\n await customFetch(`${options.directoryUrl}/api/users/${state.user.id}`, { method: 'PATCH', body: ({ plannedDeletion: null }) as any })\n readState()\n }\n\n const switchLang = (value: string) => {\n const maxAge = 60 * 60 * 24 * 365 // 1 year\n cookies.set('i18n_lang', value, { maxAge, path: cookiesPath })\n goTo(null)\n }\n\n const switchTheme = (value: Theme) => {\n const maxAge = 60 * 60 * 24 * 365 // 1 year\n cookies.set('theme', value, { maxAge, path: cookiesPath })\n goTo(null)\n }\n\n const keepalive = async () => {\n // check cookies.get('id_token') not state.user so that we do a keepalive on expired id tokens\n // as we might have an exchange token\n if (!cookies.get('id_token')) return\n if (!ssr) {\n window.localStorage.setItem('sd-keepalive' + options.sitePath, `${new Date().getTime()}`)\n }\n try {\n await customFetch(`${options.directoryUrl}/api/auth/keepalive`, { method: 'POST' })\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 401) {\n console.warn('session was expired or deleted server side')\n } else {\n throw err\n }\n }\n readState()\n }\n\n const refreshSiteInfo = async () => {\n console.warn('@data-fair/lib-vue/session refreshSiteInfo is deprecated')\n const siteInfo = await customFetch(`${options.directoryUrl}/api/sites/_public`)\n setSiteInfo(siteInfo)\n }\n\n const setSiteInfo = (siteInfo: any) => {\n if (siteInfo.theme) {\n fullSite.value = siteInfo\n const partialSite: SiteInfo = {\n main: siteInfo.main,\n isAccountMain: siteInfo.isAccountMain,\n logo: siteInfo.theme.logo,\n colors: siteInfo.theme.colors,\n authMode: siteInfo.authMode,\n authOnlyOtherSite: siteInfo.authOnlyOtherSite,\n owner: siteInfo.owner\n }\n if (theme.value == null) theme.value = getDefaultTheme(siteInfo)\n if (theme.value === 'hc') partialSite.colors = siteInfo.theme.hcColors\n if (theme.value === 'dark') {\n partialSite.colors = siteInfo.theme.darkColors\n partialSite.dark = true\n }\n if (theme.value === 'hc-dark') {\n partialSite.colors = siteInfo.theme.hcDarkColors\n partialSite.dark = true\n }\n site.value = partialSite\n } else {\n site.value = siteInfo\n }\n }\n\n if (options.siteInfo) await refreshSiteInfo()\n\n // @ts-ignore\n if (!ssr && window.__PUBLIC_SITE_INFO) setSiteInfo(window.__PUBLIC_SITE_INFO)\n\n // immediately performs a keepalive, but only on top windows (not iframes or popups)\n // and only if it was not done very recently (maybe from a refreshed page next to this one)\n // also run an auto-refresh loop\n if (!ssr && !inIframe && !('triggerCapture' in window)) {\n const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)\n\n if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > 10000) {\n await keepalive()\n }\n\n const refreshLoopDelay = 10 * 60 * 1000 // 10 minutes\n setInterval(() => {\n const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)\n if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > refreshLoopDelay / 2) {\n keepalive().catch(err => console.error(err))\n }\n }, refreshLoopDelay)\n }\n\n const session: Session = {\n state,\n organization: computed(() => state.organization),\n user: computed(() => state.user),\n account: computed(() => state.account),\n accountRole: computed(() => state.accountRole),\n siteRole: computed(() => state.siteRole),\n lang: computed(() => state.lang),\n theme: readonly(theme),\n site: shallowReadonly(site),\n fullSite: shallowReadonly(fullSite),\n loginUrl,\n login,\n logout,\n switchOrganization,\n setAdminMode,\n asAdmin,\n cancelDeletion,\n keepalive,\n refreshSiteInfo,\n switchTheme,\n switchLang,\n topLocation,\n options\n }\n\n return session\n}\n\n// uses pattern for SSR friendly plugin/composable, cf https://antfu.me/posts/composable-vue-vueday-2021#shared-state-ssr-friendly\nexport const sessionKey = Symbol('session')\nexport async function createSession (initOptions: Partial<SessionOptions>) {\n const session = await getSession(initOptions)\n return {\n ...session,\n install (app: App) { app.provide(sessionKey, session) },\n }\n}\nexport function useSession () {\n const session = inject(sessionKey)\n if (!session) throw new Error('useSession requires using the plugin createSession')\n return session as Session\n}\nexport function useSessionAuthenticated (errorBuilder?: () => any) {\n const session = useSession()\n if (!session.state.user) {\n if (errorBuilder) throw errorBuilder()\n else throw new Error('useSessionAuthenticated requires a logged in user')\n }\n return session as SessionAuthenticated\n}\n\nexport default useSession\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["session.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IncomingMessage } from 'node:http'\nimport { type Ref, type ComputedRef, type App, shallowReadonly } from 'vue'\nimport { FetchError, type fetch } from 'ofetch'\n\n// minimal structural type compatible with both vue-router v4 and v5\ninterface RouteLocationLike { fullPath: string }\nimport { type AccountKeys, type SessionState, type SessionStateAuthenticated, type User } from '@data-fair/lib-common-types/session/index.js'\nimport { reactive, computed, watch, inject, ref, shallowRef, readonly } from 'vue'\nimport { ofetch } from 'ofetch'\nimport { jwtDecode } from 'jwt-decode'\nimport cookiesModule from 'universal-cookie'\nimport Debug from 'debug'\nimport inIframe from '@data-fair/lib-utils/in-iframe.js'\n\nexport * from '@data-fair/lib-common-types/session/index.js'\n\nconst Cookies = cookiesModule as unknown as typeof cookiesModule.default\n\ninterface GenericCookies {\n get: (key: string) => string | undefined\n set: (key: string, value: string, options?: Record<string, any>) => void\n remove: (key: string) => void\n}\n\nexport interface SessionOptions {\n sitePath: string\n directoryUrl: string\n defaultLang: string\n route?: RouteLocationLike\n logoutRedirectUrl?: string\n req?: IncomingMessage\n cookies?: GenericCookies\n customFetch?: typeof fetch\n siteInfo?: boolean\n}\n\nexport interface Colors {\n background: string\n 'on-background': string\n surface: string\n 'on-surface': string\n primary: string\n 'on-primary': string\n 'text-primary': string\n secondary: string\n 'on-secondary': string\n 'text-secondary': string\n error: string\n 'on-error': string\n info: string\n 'on-info': string\n success: string\n 'on-success': string\n warning: string\n 'on-warning': string\n admin: string\n 'on-admin': string\n}\n\nexport interface FullSiteInfo {\n main?: boolean\n theme: {\n logo?: string\n colors: Colors\n dark?: boolean\n darkColors?: Colors\n hc?: boolean\n hcColors?: Colors\n hcDark?: boolean\n hcDarkColors?: Colors\n }\n}\n\nexport interface SiteInfo {\n main?: boolean\n isAccountMain?: boolean\n authMode: string\n authOnlyOtherSite?: string\n logo?: string\n dark?: boolean\n colors: Colors\n owner: AccountKeys\n}\n\nexport type AppliedTheme = 'default' | 'dark' | 'hc' | 'hc-dark'\n// `theme` cookie semantics:\n// - absent: implicit 'system' (no choice made yet)\n// - 'system': explicit \"follow the OS preference\"\n// - other: explicit override\n// In both 'system' cases the applied theme is computed at runtime via\n// resolveTheme() using prefers-color-scheme + forced-colors.\nexport type Theme = AppliedTheme | 'system'\n\nexport interface Session {\n state: SessionState\n user: ComputedRef<SessionState['user']>\n organization: ComputedRef<SessionState['organization']>\n account: ComputedRef<SessionState['account']>\n accountRole: ComputedRef<SessionState['accountRole']>\n siteRole: ComputedRef<SessionState['siteRole']>\n lang: ComputedRef<SessionState['lang']>\n theme: Ref<null | Theme>\n site: Ref<SiteInfo | null>\n fullSite: Ref<FullSiteInfo | null>\n loginUrl: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => string\n login: (redirect?: string, extraParams?: Record<string, string>, immediateRedirect?: true) => void\n logout: (redirect?: string) => Promise<void>\n switchOrganization: (org: string | null, dep?: string, role?: string, updateState?: boolean) => void\n setAdminMode: (adminMode: boolean, redirect?: string) => Promise<void>\n asAdmin: (user: any | null) => Promise<void>\n cancelDeletion: () => Promise<void>\n keepalive: () => Promise<void>\n refreshSiteInfo: () => Promise<void>\n switchTheme: (value: Theme) => void\n switchLang: (value: string) => void\n topLocation: Ref<Location | undefined>\n options: SessionOptions\n}\n\nexport type SessionAuthenticated = Omit<Session, 'state' | 'user' | 'account' | 'accountRole'> & {\n state: SessionStateAuthenticated\n user: ComputedRef<SessionStateAuthenticated['user']>\n account: ComputedRef<SessionStateAuthenticated['account']>\n accountRole: ComputedRef<SessionStateAuthenticated['accountRole']>\n}\n\nconst debug = Debug('session')\ndebug.log = console.log.bind(console)\n\n// loose shape: hosts whose Colors are partially optional (e.g. portal config) can pass their own type\nexport type ThemeOffers = {\n theme: {\n dark?: boolean\n hc?: boolean\n hcDark?: boolean\n }\n}\n\n/**\n * Resolves a user theme preference to a concrete AppliedTheme — returns the explicit choice when set,\n * otherwise picks the best variant offered by `site` based on the OS `prefers-color-scheme` / `forced-colors`\n * media queries. Always call this before handing a theme name to Vuetify: its built-in `'system'` defaultTheme\n * bypasses custom themes and falls back to its own light/dark.\n */\nexport function resolveTheme (userTheme: Theme | null, site: ThemeOffers): AppliedTheme {\n // honor an explicit choice only while `site` still offers it; otherwise fall through to\n // the OS-preference resolution below (a theme disabled after selection must not stick)\n if (userTheme === 'default') return 'default'\n if (userTheme === 'dark' && site.theme.dark) return 'dark'\n if (userTheme === 'hc' && site.theme.hc) return 'hc'\n if (userTheme === 'hc-dark' && site.theme.hcDark) return 'hc-dark'\n\n // see https://www.scottohara.me/blog/2021/10/01/detect-high-contrast-and-dark-modes.html\n const preferDark = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches\n const preferHC = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(forced-colors: active)').matches\n if (site.theme.hcDark && preferDark && preferHC) return 'hc-dark'\n if (site.theme.hc && preferHC) return 'hc'\n if (site.theme.dark && preferDark) return 'dark'\n return 'default'\n}\n\nfunction jwtDecodeAlive (jwt: string | null): User | undefined {\n if (!jwt) return\n const decoded = jwtDecode(jwt) as any\n if (!decoded) return\n const now = Math.ceil(Date.now().valueOf() / 1000)\n if (typeof decoded.exp !== 'undefined' && decoded.exp < now) {\n // token expired\n return\n }\n if (typeof decoded.nbf !== 'undefined' && decoded.nbf > now) {\n console.warn(`token not yet valid: ${decoded.nbf}>${now}, ${JSON.stringify(decoded)}`)\n // do not return here, this is probably a false flag due to a slightly mismatched clock\n }\n return decoded as User\n}\n\nconst getTopLocation = () => {\n try {\n return window.top ? window.top.location : window.location\n } catch (err) {\n return window.location\n }\n}\n\nconst goTo = (url: string | null) => {\n const topLocation = getTopLocation()\n if (topLocation == null) {\n throw new TypeError('session.goTo was called without access to the window object or its location')\n }\n if (url) topLocation.href = url\n else topLocation.reload()\n}\n\nconst defaultOptions = { directoryUrl: '/simple-directory', sitePath: '', defaultLang: 'fr' }\n\nexport async function getSession (initOptions: Partial<SessionOptions>): Promise<Session> {\n const options = { ...defaultOptions, ...initOptions }\n const cookiesPath = options.sitePath + '/'\n debug(`init directoryUrl=${options.directoryUrl}, cookiesPath=${cookiesPath}`)\n const ssr = !!options.req\n if (ssr) debug('run in SSR context')\n\n const customFetch = initOptions?.customFetch ?? ofetch\n\n // use vue-router to detect page change and maintain a reference to the current page location\n // top page if we are in iframe context\n const topLocation = computed(() => {\n if (ssr) return undefined\n\n if (options.route?.fullPath) { /* empty */ } // adds reactivity\n const location = getTopLocation()\n debug('update location based on route change', location)\n return location\n })\n\n // the core state of the session that is filled by reading cookies\n const state = reactive({} as SessionState)\n const fullSite = shallowRef<FullSiteInfo | null>(null)\n const site = shallowRef<SiteInfo | null>(null)\n const theme = ref<Theme | null>(null)\n\n // cookies are the source of truth and this information is transformed into the state reactive object\n const cookies = initOptions?.cookies ?? new Cookies(options.req?.headers.cookie)\n const readState = () => {\n // absent cookie is treated as implicit 'system' so consumers (theme-switcher\n // radios, host plugins) always have a meaningful value to bind to.\n theme.value = (cookies.get('theme') as Theme | undefined) ?? 'system'\n\n const langCookie = cookies.get('i18n_lang')\n state.lang = langCookie ?? options.defaultLang\n\n const idToken = cookies.get('id_token')\n const user = jwtDecodeAlive(idToken)\n\n if (!user) {\n delete state.user\n delete state.organization\n delete state.account\n delete state.accountRole\n return\n }\n\n // this is to prevent null values that are put by SD versions that do not strictly respect their schema\n for (const org of user.organizations) {\n if (!org.department) {\n delete org.department\n delete org.departmentName\n }\n }\n\n state.user = user\n const organizationId = cookies.get('id_token_org')\n const departmentId = cookies.get('id_token_dep')\n const switchedRole = cookies.get('id_token_role')\n if (organizationId) {\n state.organization = state.user.organizations.find(o => {\n if (o.id !== organizationId) return false\n if (departmentId && departmentId !== o.department) return false\n if (switchedRole && switchedRole !== o.role) return false\n return true\n })\n } else {\n delete state.organization\n }\n if (state.organization) {\n state.account = {\n type: 'organization',\n id: state.organization.id,\n name: state.organization.name,\n department: state.organization.department,\n departmentName: state.organization.departmentName\n }\n state.accountRole = state.organization.role\n } else {\n state.account = {\n type: 'user',\n id: state.user.id,\n name: state.user.name\n }\n state.accountRole = 'admin'\n }\n\n if (state.user?.siteOwner) {\n if (state.user.siteOwner.type === 'user' && state.user.siteOwner.id === state.user.id) {\n state.siteRole = 'admin'\n }\n if (state.user.siteOwner.type === 'organization' && state.user.siteOwner.id === state.organization?.id) {\n state.siteRole = state.organization.role\n }\n }\n }\n readState()\n debug('initial state', state)\n\n if (!ssr) {\n // sessionData is also stored in localStorage as a way to access it in simpler pages that do not require use-session\n // and in order to listen to storage event from other contexts and sync session info accross windows and tabs\n const storageListener = (event: StorageEvent) => {\n if (event.key === 'sd-session' + options.sitePath) readState()\n }\n window.addEventListener('storage', storageListener)\n\n // we cannot use onUnmounted here or we get warnings \"onUnmounted is called when there is no active component instance to be associated with. \"\n // TODO: should we have another cleanup mechanism ?\n // onUnmounted(() => { window.removeEventListener('storage', storageListener) })\n\n // trigger some full page refresh when some key session elements are changed\n // the danger of simply using reactivity is too high, data must be re-fetched, etc.\n watch(() => state.account, (account, oldAccount) => {\n if (account?.type !== oldAccount?.type || account?.id !== oldAccount?.id || account?.department !== oldAccount?.department) {\n goTo(null)\n }\n })\n watch(() => state.lang, () => {\n goTo(null)\n })\n watch(() => state.dark, () => {\n goTo(null)\n })\n watch(state, (state) => {\n if (!ssr) {\n window.localStorage.setItem('sd-session' + options.sitePath, JSON.stringify(state))\n }\n debug('state changed', state)\n })\n }\n\n // login can be performed as a simple link (please use target=top) or as a function\n function loginUrl (redirect?: string, extraParams: Record<string, string> = {}, immediateRedirect = true): string {\n // login can also be used to redirect user immediately if he is already logged\n if (redirect && state.user && immediateRedirect) return redirect\n if (!redirect && topLocation.value) redirect = topLocation.value.href\n let url = `${options.directoryUrl}/login?redirect=${encodeURIComponent(redirect ?? '')}`\n Object.keys(extraParams).filter(key => ![null, undefined, ''].includes(extraParams[key])).forEach((key) => {\n url += `&${key}=${encodeURIComponent(extraParams[key])}`\n })\n return url\n }\n const login = (redirect?: string, extraParams: Record<string, string> = {}, immediateRedirect = true) => {\n goTo(loginUrl(redirect, extraParams, immediateRedirect))\n }\n const logout = async (redirect?: string) => {\n const response = await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' }) as { endSessionUrl?: string } | undefined\n // sometimes server side cookie deletion is not applied immediately in browser local js context\n // so we do it here to\n cookies.remove('id_token')\n cookies.remove('id_token_org')\n cookies.remove('id_token_dep')\n cookies.remove('id_token_role')\n // RP-Initiated Logout: if the server returned an endSessionUrl, redirect to the SSO logout\n if (response?.endSessionUrl) {\n goTo(response.endSessionUrl)\n } else {\n goTo(redirect ?? options.logoutRedirectUrl ?? null)\n }\n }\n\n const switchOrganization = (org: string | null, dep?: string, role?: string, updateState = true) => {\n const cookieOpts = { path: cookiesPath }\n if (org) cookies.set('id_token_org', org, cookieOpts)\n else cookies.remove('id_token_org', cookieOpts)\n if (dep) cookies.set('id_token_dep', dep, cookieOpts)\n else cookies.remove('id_token_dep', cookieOpts)\n if (role) cookies.set('id_token_role', role, cookieOpts)\n else cookies.remove('id_token_role', cookieOpts)\n if (updateState) readState()\n }\n\n const setAdminMode = async (adminMode: boolean, redirect?: string) => {\n if (adminMode) {\n const params: Record<string, string> = { adminMode: 'true' }\n if (state.user != null) params.email = state.user.email\n // preserve current active org/dep\n if (state.organization) {\n params.org = state.organization.id\n if (state.organization.department) params.dep = state.organization.department\n }\n const url = loginUrl(redirect, params, true)\n goTo(url)\n } else {\n await customFetch(`${options.directoryUrl}/api/auth/adminmode`, { method: 'DELETE' })\n goTo(redirect ?? null)\n }\n }\n\n const asAdmin = async (user: any | null) => {\n if (user) {\n await customFetch(`${options.directoryUrl}/api/auth/asadmin`, { method: 'POST', body: user })\n } else {\n await customFetch(`${options.directoryUrl}/api/auth/asadmin`, { method: 'DELETE' })\n }\n goTo(null)\n }\n\n const cancelDeletion = async () => {\n if (state.user == null) return\n await customFetch(`${options.directoryUrl}/api/users/${state.user.id}`, { method: 'PATCH', body: ({ plannedDeletion: null }) as any })\n readState()\n }\n\n const switchLang = (value: string) => {\n const maxAge = 60 * 60 * 24 * 365 // 1 year\n cookies.set('i18n_lang', value, { maxAge, path: cookiesPath })\n goTo(null)\n }\n\n const switchTheme = (value: Theme) => {\n // an absent cookie already means 'system' (see init above), so don't persist it explicitly\n if (value === 'system') {\n cookies.remove('theme', { path: cookiesPath })\n } else {\n const maxAge = 60 * 60 * 24 * 365 // 1 year\n cookies.set('theme', value, { maxAge, path: cookiesPath })\n }\n goTo(null)\n }\n\n const keepalive = async () => {\n // check cookies.get('id_token') not state.user so that we do a keepalive on expired id tokens\n // as we might have an exchange token\n if (!cookies.get('id_token')) return\n if (!ssr) {\n window.localStorage.setItem('sd-keepalive' + options.sitePath, `${new Date().getTime()}`)\n }\n try {\n await customFetch(`${options.directoryUrl}/api/auth/keepalive`, { method: 'POST' })\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 401) {\n console.warn('session was expired or deleted server side')\n } else {\n throw err\n }\n }\n readState()\n }\n\n const refreshSiteInfo = async () => {\n console.warn('@data-fair/lib-vue/session refreshSiteInfo is deprecated')\n const siteInfo = await customFetch(`${options.directoryUrl}/api/sites/_public`)\n setSiteInfo(siteInfo)\n }\n\n const setSiteInfo = (siteInfo: any) => {\n if (siteInfo.theme) {\n fullSite.value = siteInfo\n const partialSite: SiteInfo = {\n main: siteInfo.main,\n isAccountMain: siteInfo.isAccountMain,\n logo: siteInfo.theme.logo,\n colors: siteInfo.theme.colors,\n authMode: siteInfo.authMode,\n authOnlyOtherSite: siteInfo.authOnlyOtherSite,\n owner: siteInfo.owner\n }\n const applied = resolveTheme(theme.value, siteInfo)\n if (applied === 'hc') partialSite.colors = siteInfo.theme.hcColors\n if (applied === 'dark') {\n partialSite.colors = siteInfo.theme.darkColors\n partialSite.dark = true\n }\n if (applied === 'hc-dark') {\n partialSite.colors = siteInfo.theme.hcDarkColors\n partialSite.dark = true\n }\n site.value = partialSite\n } else {\n site.value = siteInfo\n }\n }\n\n if (options.siteInfo) await refreshSiteInfo()\n\n // @ts-ignore\n if (!ssr && window.__PUBLIC_SITE_INFO) setSiteInfo(window.__PUBLIC_SITE_INFO)\n\n // re-apply the theme when the OS preference changes while the user is on\n // 'system'. Important for mobile devices that switch light/dark over the day.\n if (!ssr && typeof window !== 'undefined' && window.matchMedia) {\n const onOsPrefChange = () => {\n if (theme.value === 'system' && fullSite.value) setSiteInfo(fullSite.value)\n }\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', onOsPrefChange)\n window.matchMedia('(forced-colors: active)').addEventListener('change', onOsPrefChange)\n }\n\n // immediately performs a keepalive, but only on top windows (not iframes or popups)\n // and only if it was not done very recently (maybe from a refreshed page next to this one)\n // also run an auto-refresh loop\n if (!ssr && !inIframe && !('triggerCapture' in window)) {\n const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)\n\n if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > 10000) {\n await keepalive()\n }\n\n const refreshLoopDelay = 10 * 60 * 1000 // 10 minutes\n setInterval(() => {\n const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath)\n if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > refreshLoopDelay / 2) {\n keepalive().catch(err => console.error(err))\n }\n }, refreshLoopDelay)\n }\n\n const session: Session = {\n state,\n organization: computed(() => state.organization),\n user: computed(() => state.user),\n account: computed(() => state.account),\n accountRole: computed(() => state.accountRole),\n siteRole: computed(() => state.siteRole),\n lang: computed(() => state.lang),\n theme: readonly(theme),\n site: shallowReadonly(site),\n fullSite: shallowReadonly(fullSite),\n loginUrl,\n login,\n logout,\n switchOrganization,\n setAdminMode,\n asAdmin,\n cancelDeletion,\n keepalive,\n refreshSiteInfo,\n switchTheme,\n switchLang,\n topLocation,\n options\n }\n\n return session\n}\n\n// uses pattern for SSR friendly plugin/composable, cf https://antfu.me/posts/composable-vue-vueday-2021#shared-state-ssr-friendly\nexport const sessionKey = Symbol('session')\nexport async function createSession (initOptions: Partial<SessionOptions>) {\n const session = await getSession(initOptions)\n return {\n ...session,\n install (app: App) { app.provide(sessionKey, session) },\n }\n}\nexport function useSession () {\n const session = inject(sessionKey)\n if (!session) throw new Error('useSession requires using the plugin createSession')\n return session as Session\n}\nexport function useSessionAuthenticated (errorBuilder?: () => any) {\n const session = useSession()\n if (!session.state.user) {\n if (errorBuilder) throw errorBuilder()\n else throw new Error('useSessionAuthenticated requires a logged in user')\n }\n return session as SessionAuthenticated\n}\n\nexport default useSession\n"]}
|