@data-fair/lib-vue 1.28.0 → 1.29.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/auto-scroll-bottom.d.ts +12 -4
- package/auto-scroll-bottom.js +15 -11
- package/auto-scroll-bottom.js.map +1 -1
- package/package.json +1 -1
- package/session.d.ts +20 -5
- package/session.js +36 -11
- package/session.js.map +1 -1
package/auto-scroll-bottom.d.ts
CHANGED
|
@@ -7,15 +7,23 @@ import { type MaybeRefOrGetter } from 'vue';
|
|
|
7
7
|
* `target` is what actually scrolls — pass `window` (or the current document's
|
|
8
8
|
* scroller) for a page that scrolls as a whole, or a getter returning the inner
|
|
9
9
|
* scrollable element when the growing region lives inside an `overflow: auto`
|
|
10
|
-
* container.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* container.
|
|
11
|
+
*
|
|
12
|
+
* Following is driven by the bottom being in view (`arrivedState.bottom`), not
|
|
13
|
+
* by scroll direction: when the content shrinks (a loader removed, a panel
|
|
14
|
+
* collapsed) the browser clamps scrollTop upward, and a direction-based check
|
|
15
|
+
* would mistake that for the user scrolling away and stop following for good.
|
|
16
|
+
*
|
|
17
|
+
* "In view" allows a small margin (`bottomThreshold`): exact scrollTop rarely
|
|
18
|
+
* reaches the very bottom (sub-pixel rounding) and live content keeps appending,
|
|
19
|
+
* so a 0px check could never re-arm following once the user had scrolled away.
|
|
13
20
|
*
|
|
14
21
|
* @param target the scroll container: `window`, an element, or a ref/getter to
|
|
15
22
|
* one (tolerates `null`/`undefined` while the element is not yet mounted)
|
|
16
23
|
* @param growthSignal reactive getter for the content length (the growth signal)
|
|
17
24
|
* @param isActive getter telling whether the source is still streaming/growing
|
|
25
|
+
* @param bottomThreshold px from the bottom still counted as "at the bottom"
|
|
18
26
|
*/
|
|
19
|
-
export declare const useAutoScrollBottom: (target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>, growthSignal: () => number, isActive: () => boolean) => {
|
|
27
|
+
export declare const useAutoScrollBottom: (target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>, growthSignal: () => number, isActive: () => boolean, bottomThreshold?: number) => {
|
|
20
28
|
following: import("vue").Ref<boolean, boolean>;
|
|
21
29
|
};
|
package/auto-scroll-bottom.js
CHANGED
|
@@ -8,26 +8,30 @@ import { useScroll, useEventListener } from '@vueuse/core';
|
|
|
8
8
|
* `target` is what actually scrolls — pass `window` (or the current document's
|
|
9
9
|
* scroller) for a page that scrolls as a whole, or a getter returning the inner
|
|
10
10
|
* scrollable element when the growing region lives inside an `overflow: auto`
|
|
11
|
-
* container.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* container.
|
|
12
|
+
*
|
|
13
|
+
* Following is driven by the bottom being in view (`arrivedState.bottom`), not
|
|
14
|
+
* by scroll direction: when the content shrinks (a loader removed, a panel
|
|
15
|
+
* collapsed) the browser clamps scrollTop upward, and a direction-based check
|
|
16
|
+
* would mistake that for the user scrolling away and stop following for good.
|
|
17
|
+
*
|
|
18
|
+
* "In view" allows a small margin (`bottomThreshold`): exact scrollTop rarely
|
|
19
|
+
* reaches the very bottom (sub-pixel rounding) and live content keeps appending,
|
|
20
|
+
* so a 0px check could never re-arm following once the user had scrolled away.
|
|
14
21
|
*
|
|
15
22
|
* @param target the scroll container: `window`, an element, or a ref/getter to
|
|
16
23
|
* one (tolerates `null`/`undefined` while the element is not yet mounted)
|
|
17
24
|
* @param growthSignal reactive getter for the content length (the growth signal)
|
|
18
25
|
* @param isActive getter telling whether the source is still streaming/growing
|
|
26
|
+
* @param bottomThreshold px from the bottom still counted as "at the bottom"
|
|
19
27
|
*/
|
|
20
|
-
export const useAutoScrollBottom = (target, growthSignal, isActive) => {
|
|
28
|
+
export const useAutoScrollBottom = (target, growthSignal, isActive, bottomThreshold = 48) => {
|
|
21
29
|
// Start following so a freshly opened, still-growing source pins to its tail
|
|
22
30
|
// even though it usually mounts scrolled to the top.
|
|
23
31
|
const following = ref(true);
|
|
24
|
-
const { arrivedState,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
following.value = false; // scrolled up → stop
|
|
28
|
-
else if (arrivedState.bottom)
|
|
29
|
-
following.value = true; // back at bottom → resume
|
|
30
|
-
}
|
|
32
|
+
const { arrivedState, y } = useScroll(target, {
|
|
33
|
+
offset: { bottom: bottomThreshold },
|
|
34
|
+
onScroll: () => { following.value = arrivedState.bottom; } // near bottom → follow, else stop
|
|
31
35
|
});
|
|
32
36
|
// A wheel-up reaches us even when the target can't scroll (short content, or
|
|
33
37
|
// an auto-height embed where a parent scrolls) — the only "stop following"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-scroll-bottom.js","sourceRoot":"","sources":["auto-scroll-bottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAyB,MAAM,KAAK,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE1D
|
|
1
|
+
{"version":3,"file":"auto-scroll-bottom.js","sourceRoot":"","sources":["auto-scroll-bottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAyB,MAAM,KAAK,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAiE,EACjE,YAA0B,EAC1B,QAAuB,EACvB,eAAe,GAAG,EAAE,EACpB,EAAE;IACF,6EAA6E;IAC7E,qDAAqD;IACrD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAE3B,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE;QAC5C,MAAM,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;QACnC,QAAQ,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,GAAG,YAAY,CAAC,MAAM,CAAA,CAAC,CAAC,CAAC,kCAAkC;KAC7F,CAAC,CAAA;IAEF,6EAA6E;IAC7E,2EAA2E;IAC3E,0BAA0B;IAC1B,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAa,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAA,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAEtH,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,0EAA0E;QAC1E,kEAAkE;QAClE,CAAC,CAAC,KAAK,GAAG,EAAE,YAAY,MAAM;YAC5B,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,YAAY;YACtE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAA;IACrB,CAAC,CAAA;IAED,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI,QAAQ,EAAE,IAAI,SAAS,CAAC,KAAK;QAAE,WAAW,EAAE,CAAA,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAElG,OAAO,EAAE,SAAS,EAAE,CAAA;AACtB,CAAC,CAAA","sourcesContent":["import { ref, watch, toValue, type MaybeRefOrGetter } from 'vue'\nimport { useScroll, useEventListener } from '@vueuse/core'\n\n/**\n * Stick-to-bottom autoscroll for a growing, live region (a run log, a chat\n * transcript, ...): follows new content while the user is at the bottom, any\n * upward scroll or wheel-up stops it, scrolling back to the bottom resumes.\n *\n * `target` is what actually scrolls — pass `window` (or the current document's\n * scroller) for a page that scrolls as a whole, or a getter returning the inner\n * scrollable element when the growing region lives inside an `overflow: auto`\n * container.\n *\n * Following is driven by the bottom being in view (`arrivedState.bottom`), not\n * by scroll direction: when the content shrinks (a loader removed, a panel\n * collapsed) the browser clamps scrollTop upward, and a direction-based check\n * would mistake that for the user scrolling away and stop following for good.\n *\n * \"In view\" allows a small margin (`bottomThreshold`): exact scrollTop rarely\n * reaches the very bottom (sub-pixel rounding) and live content keeps appending,\n * so a 0px check could never re-arm following once the user had scrolled away.\n *\n * @param target the scroll container: `window`, an element, or a ref/getter to\n * one (tolerates `null`/`undefined` while the element is not yet mounted)\n * @param growthSignal reactive getter for the content length (the growth signal)\n * @param isActive getter telling whether the source is still streaming/growing\n * @param bottomThreshold px from the bottom still counted as \"at the bottom\"\n */\nexport const useAutoScrollBottom = (\n target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>,\n growthSignal: () => number,\n isActive: () => boolean,\n bottomThreshold = 48\n) => {\n // Start following so a freshly opened, still-growing source pins to its tail\n // even though it usually mounts scrolled to the top.\n const following = ref(true)\n\n const { arrivedState, y } = useScroll(target, {\n offset: { bottom: bottomThreshold },\n onScroll: () => { following.value = arrivedState.bottom } // near bottom → follow, else stop\n })\n\n // A wheel-up reaches us even when the target can't scroll (short content, or\n // an auto-height embed where a parent scrolls) — the only \"stop following\"\n // signal available there.\n useEventListener(target, 'wheel', (e: WheelEvent) => { if (e.deltaY < 0) following.value = false }, { passive: true })\n\n const pinToBottom = () => {\n const el = toValue(target)\n if (!el) return\n // For an element, `y` sets its scrollTop; for the window we scroll to the\n // document's full height (window has no scrollHeight of its own).\n y.value = el instanceof Window\n ? (document.scrollingElement ?? document.documentElement).scrollHeight\n : el.scrollHeight\n }\n\n watch(growthSignal, () => { if (isActive() && following.value) pinToBottom() }, { flush: 'post' })\n\n return { following }\n}\n"]}
|
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,18 @@ 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
|
+
if (userTheme && userTheme !== 'system')
|
|
21
|
+
return userTheme;
|
|
14
22
|
// 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;
|
|
23
|
+
const preferDark = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
24
|
+
const preferHC = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(forced-colors: active)').matches;
|
|
17
25
|
if (site.theme.hcDark && preferDark && preferHC)
|
|
18
26
|
return 'hc-dark';
|
|
19
27
|
if (site.theme.hc && preferHC)
|
|
@@ -84,7 +92,9 @@ export async function getSession(initOptions) {
|
|
|
84
92
|
// cookies are the source of truth and this information is transformed into the state reactive object
|
|
85
93
|
const cookies = initOptions?.cookies ?? new Cookies(options.req?.headers.cookie);
|
|
86
94
|
const readState = () => {
|
|
87
|
-
|
|
95
|
+
// absent cookie is treated as implicit 'system' so consumers (theme-switcher
|
|
96
|
+
// radios, host plugins) always have a meaningful value to bind to.
|
|
97
|
+
theme.value = cookies.get('theme') ?? 'system';
|
|
88
98
|
const langCookie = cookies.get('i18n_lang');
|
|
89
99
|
state.lang = langCookie ?? options.defaultLang;
|
|
90
100
|
const idToken = cookies.get('id_token');
|
|
@@ -198,14 +208,20 @@ export async function getSession(initOptions) {
|
|
|
198
208
|
goTo(loginUrl(redirect, extraParams, immediateRedirect));
|
|
199
209
|
};
|
|
200
210
|
const logout = async (redirect) => {
|
|
201
|
-
await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' });
|
|
211
|
+
const response = await customFetch(`${options.directoryUrl}/api/auth`, { method: 'DELETE' });
|
|
202
212
|
// sometimes server side cookie deletion is not applied immediately in browser local js context
|
|
203
213
|
// so we do it here to
|
|
204
214
|
cookies.remove('id_token');
|
|
205
215
|
cookies.remove('id_token_org');
|
|
206
216
|
cookies.remove('id_token_dep');
|
|
207
217
|
cookies.remove('id_token_role');
|
|
208
|
-
|
|
218
|
+
// RP-Initiated Logout: if the server returned an endSessionUrl, redirect to the SSO logout
|
|
219
|
+
if (response?.endSessionUrl) {
|
|
220
|
+
goTo(response.endSessionUrl);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
goTo(redirect ?? options.logoutRedirectUrl ?? null);
|
|
224
|
+
}
|
|
209
225
|
};
|
|
210
226
|
const switchOrganization = (org, dep, role, updateState = true) => {
|
|
211
227
|
const cookieOpts = { path: cookiesPath };
|
|
@@ -306,15 +322,14 @@ export async function getSession(initOptions) {
|
|
|
306
322
|
authOnlyOtherSite: siteInfo.authOnlyOtherSite,
|
|
307
323
|
owner: siteInfo.owner
|
|
308
324
|
};
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (theme.value === 'hc')
|
|
325
|
+
const applied = resolveTheme(theme.value, siteInfo);
|
|
326
|
+
if (applied === 'hc')
|
|
312
327
|
partialSite.colors = siteInfo.theme.hcColors;
|
|
313
|
-
if (
|
|
328
|
+
if (applied === 'dark') {
|
|
314
329
|
partialSite.colors = siteInfo.theme.darkColors;
|
|
315
330
|
partialSite.dark = true;
|
|
316
331
|
}
|
|
317
|
-
if (
|
|
332
|
+
if (applied === 'hc-dark') {
|
|
318
333
|
partialSite.colors = siteInfo.theme.hcDarkColors;
|
|
319
334
|
partialSite.dark = true;
|
|
320
335
|
}
|
|
@@ -329,6 +344,16 @@ export async function getSession(initOptions) {
|
|
|
329
344
|
// @ts-ignore
|
|
330
345
|
if (!ssr && window.__PUBLIC_SITE_INFO)
|
|
331
346
|
setSiteInfo(window.__PUBLIC_SITE_INFO);
|
|
347
|
+
// re-apply the theme when the OS preference changes while the user is on
|
|
348
|
+
// 'system'. Important for mobile devices that switch light/dark over the day.
|
|
349
|
+
if (!ssr && typeof window !== 'undefined' && window.matchMedia) {
|
|
350
|
+
const onOsPrefChange = () => {
|
|
351
|
+
if (theme.value === 'system' && fullSite.value)
|
|
352
|
+
setSiteInfo(fullSite.value);
|
|
353
|
+
};
|
|
354
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', onOsPrefChange);
|
|
355
|
+
window.matchMedia('(forced-colors: active)').addEventListener('change', onOsPrefChange);
|
|
356
|
+
}
|
|
332
357
|
// immediately performs a keepalive, but only on top windows (not iframes or popups)
|
|
333
358
|
// and only if it was not done very recently (maybe from a refreshed page next to this one)
|
|
334
359
|
// 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 if (userTheme && userTheme !== 'system') return userTheme\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 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 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"]}
|