nextjs-cms 0.5.9 → 0.5.10
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/dist/api/axios/axiosInstance.d.ts +1 -1
- package/dist/api/axios/axiosInstance.js +8 -8
- package/dist/api/index.d.ts +855 -855
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +12 -12
- package/dist/api/lib/serverActions.d.ts +239 -239
- package/dist/api/lib/serverActions.d.ts.map +1 -1
- package/dist/api/lib/serverActions.js +834 -834
- package/dist/api/root.d.ts +828 -828
- package/dist/api/root.js +30 -30
- package/dist/api/routers/accountSettings.d.ts +60 -60
- package/dist/api/routers/accountSettings.js +108 -108
- package/dist/api/routers/admins.d.ts +105 -105
- package/dist/api/routers/admins.js +219 -219
- package/dist/api/routers/auth.d.ts +47 -47
- package/dist/api/routers/auth.js +25 -25
- package/dist/api/routers/categorySection.d.ts +103 -103
- package/dist/api/routers/categorySection.js +38 -38
- package/dist/api/routers/cmsSettings.d.ts +48 -48
- package/dist/api/routers/cmsSettings.js +51 -51
- package/dist/api/routers/cpanel.d.ts +83 -83
- package/dist/api/routers/cpanel.js +216 -216
- package/dist/api/routers/files.d.ts +47 -47
- package/dist/api/routers/files.js +23 -23
- package/dist/api/routers/gallery.d.ts +35 -35
- package/dist/api/routers/gallery.js +62 -62
- package/dist/api/routers/googleAnalytics.d.ts +30 -30
- package/dist/api/routers/googleAnalytics.js +7 -7
- package/dist/api/routers/hasItemsSection.d.ts +139 -139
- package/dist/api/routers/hasItemsSection.js +34 -34
- package/dist/api/routers/navigation.d.ts +51 -51
- package/dist/api/routers/navigation.js +11 -11
- package/dist/api/routers/simpleSection.d.ts +57 -57
- package/dist/api/routers/simpleSection.js +12 -12
- package/dist/api/trpc.d.ts +106 -106
- package/dist/api/trpc.js +72 -72
- package/dist/auth/axios/axiosInstance.d.ts +1 -1
- package/dist/auth/axios/axiosInstance.js +8 -8
- package/dist/auth/csrf.d.ts +29 -29
- package/dist/auth/csrf.js +76 -76
- package/dist/auth/hooks/index.d.ts +3 -3
- package/dist/auth/hooks/index.d.ts.map +1 -1
- package/dist/auth/hooks/index.js +3 -3
- package/dist/auth/hooks/useAxiosPrivate.d.ts +4 -4
- package/dist/auth/hooks/useAxiosPrivate.js +74 -74
- package/dist/auth/hooks/useRefreshToken.d.ts +6 -6
- package/dist/auth/hooks/useRefreshToken.js +79 -79
- package/dist/auth/index.d.ts +22 -22
- package/dist/auth/index.js +44 -44
- package/dist/auth/jwt.d.ts +5 -5
- package/dist/auth/jwt.js +25 -25
- package/dist/auth/lib/actions.d.ts +32 -32
- package/dist/auth/lib/actions.d.ts.map +1 -1
- package/dist/auth/lib/actions.js +209 -209
- package/dist/auth/lib/client.d.ts +3 -3
- package/dist/auth/lib/client.js +46 -46
- package/dist/auth/lib/index.d.ts +2 -2
- package/dist/auth/lib/index.d.ts.map +1 -1
- package/dist/auth/lib/index.js +2 -2
- package/dist/auth/react.d.ts +105 -105
- package/dist/auth/react.d.ts.map +1 -1
- package/dist/auth/react.js +347 -347
- package/dist/auth/trpc.d.ts +5 -5
- package/dist/auth/trpc.d.ts.map +1 -1
- package/dist/auth/trpc.js +81 -81
- package/dist/core/config/config-loader.d.ts +91 -91
- package/dist/core/config/config-loader.js +230 -230
- package/dist/core/config/index.d.ts +2 -2
- package/dist/core/config/index.d.ts.map +1 -1
- package/dist/core/config/index.js +1 -1
- package/dist/core/config/loader.d.ts +1 -1
- package/dist/core/config/loader.js +42 -42
- package/dist/core/db/index.d.ts +1 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +1 -1
- package/dist/core/db/table-checker/DbTable.d.ts +5 -5
- package/dist/core/db/table-checker/DbTable.js +5 -5
- package/dist/core/db/table-checker/MysqlTable.d.ts +33 -33
- package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -1
- package/dist/core/db/table-checker/MysqlTable.js +94 -94
- package/dist/core/db/table-checker/index.d.ts +1 -1
- package/dist/core/db/table-checker/index.d.ts.map +1 -1
- package/dist/core/db/table-checker/index.js +1 -1
- package/dist/core/factories/FieldFactory.d.ts +123 -123
- package/dist/core/factories/FieldFactory.d.ts.map +1 -1
- package/dist/core/factories/FieldFactory.js +411 -411
- package/dist/core/factories/SectionFactory.d.ts +109 -109
- package/dist/core/factories/SectionFactory.d.ts.map +1 -1
- package/dist/core/factories/SectionFactory.js +415 -415
- package/dist/core/factories/index.d.ts +2 -2
- package/dist/core/factories/index.d.ts.map +1 -1
- package/dist/core/factories/index.js +2 -2
- package/dist/core/fields/checkbox.d.ts +62 -62
- package/dist/core/fields/checkbox.d.ts.map +1 -1
- package/dist/core/fields/checkbox.js +62 -62
- package/dist/core/fields/color.d.ts +83 -83
- package/dist/core/fields/color.d.ts.map +1 -1
- package/dist/core/fields/color.js +91 -91
- package/dist/core/fields/date.d.ts +99 -99
- package/dist/core/fields/date.d.ts.map +1 -1
- package/dist/core/fields/date.js +108 -108
- package/dist/core/fields/document.d.ts +179 -179
- package/dist/core/fields/document.d.ts.map +1 -1
- package/dist/core/fields/document.js +277 -277
- package/dist/core/fields/field-group.d.ts +17 -17
- package/dist/core/fields/field-group.d.ts.map +1 -1
- package/dist/core/fields/field-group.js +6 -6
- package/dist/core/fields/field.d.ts +125 -125
- package/dist/core/fields/field.d.ts.map +1 -1
- package/dist/core/fields/field.js +148 -148
- package/dist/core/fields/fileField.d.ts +14 -14
- package/dist/core/fields/fileField.d.ts.map +1 -1
- package/dist/core/fields/fileField.js +5 -5
- package/dist/core/fields/index.d.ts +64 -64
- package/dist/core/fields/index.d.ts.map +1 -1
- package/dist/core/fields/index.js +18 -18
- package/dist/core/fields/map.d.ts +166 -166
- package/dist/core/fields/map.d.ts.map +1 -1
- package/dist/core/fields/map.js +152 -152
- package/dist/core/fields/number.d.ts +185 -185
- package/dist/core/fields/number.d.ts.map +1 -1
- package/dist/core/fields/number.js +241 -241
- package/dist/core/fields/password.d.ts +108 -108
- package/dist/core/fields/password.d.ts.map +1 -1
- package/dist/core/fields/password.js +133 -133
- package/dist/core/fields/photo.d.ts +288 -288
- package/dist/core/fields/photo.d.ts.map +1 -1
- package/dist/core/fields/photo.js +410 -410
- package/dist/core/fields/richText.d.ts +294 -294
- package/dist/core/fields/richText.d.ts.map +1 -1
- package/dist/core/fields/richText.js +338 -338
- package/dist/core/fields/select.d.ts +365 -365
- package/dist/core/fields/select.d.ts.map +1 -1
- package/dist/core/fields/select.js +499 -499
- package/dist/core/fields/selectMultiple.d.ts +235 -235
- package/dist/core/fields/selectMultiple.d.ts.map +1 -1
- package/dist/core/fields/selectMultiple.js +417 -417
- package/dist/core/fields/tags.d.ts +130 -130
- package/dist/core/fields/tags.d.ts.map +1 -1
- package/dist/core/fields/tags.js +105 -105
- package/dist/core/fields/text.d.ts +135 -135
- package/dist/core/fields/text.d.ts.map +1 -1
- package/dist/core/fields/text.js +157 -157
- package/dist/core/fields/textArea.d.ts +106 -106
- package/dist/core/fields/textArea.d.ts.map +1 -1
- package/dist/core/fields/textArea.js +126 -126
- package/dist/core/fields/video.d.ts +147 -147
- package/dist/core/fields/video.d.ts.map +1 -1
- package/dist/core/fields/video.js +248 -248
- package/dist/core/helpers/entity.d.ts +7 -7
- package/dist/core/helpers/entity.js +27 -27
- package/dist/core/helpers/index.d.ts +4 -4
- package/dist/core/helpers/index.d.ts.map +1 -1
- package/dist/core/helpers/index.js +3 -3
- package/dist/core/index.d.ts +7 -7
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -7
- package/dist/core/sections/category.d.ts +282 -282
- package/dist/core/sections/category.d.ts.map +1 -1
- package/dist/core/sections/category.js +147 -147
- package/dist/core/sections/hasItems.d.ts +631 -631
- package/dist/core/sections/hasItems.d.ts.map +1 -1
- package/dist/core/sections/hasItems.js +144 -144
- package/dist/core/sections/index.d.ts +4 -4
- package/dist/core/sections/index.d.ts.map +1 -1
- package/dist/core/sections/index.js +4 -4
- package/dist/core/sections/section.d.ts +225 -225
- package/dist/core/sections/section.d.ts.map +1 -1
- package/dist/core/sections/section.js +341 -341
- package/dist/core/sections/simple.d.ts +98 -98
- package/dist/core/sections/simple.d.ts.map +1 -1
- package/dist/core/sections/simple.js +95 -95
- package/dist/core/security/dom.d.ts +10 -10
- package/dist/core/security/dom.js +92 -92
- package/dist/core/submit/ItemEditSubmit.d.ts +75 -75
- package/dist/core/submit/ItemEditSubmit.js +186 -186
- package/dist/core/submit/NewItemSubmit.d.ts +13 -13
- package/dist/core/submit/NewItemSubmit.js +93 -93
- package/dist/core/submit/SimpleSectionSubmit.d.ts +12 -12
- package/dist/core/submit/SimpleSectionSubmit.js +93 -93
- package/dist/core/submit/index.d.ts +4 -4
- package/dist/core/submit/index.js +4 -4
- package/dist/core/submit/submit.d.ts +115 -115
- package/dist/core/submit/submit.js +479 -479
- package/dist/core/types/index.d.ts +279 -279
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js +1 -1
- package/dist/db/client.d.ts +8 -8
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +19 -19
- package/dist/db/config.d.ts +5 -5
- package/dist/db/config.js +22 -22
- package/dist/db/drizzle.config.d.ts +5 -5
- package/dist/db/drizzle.config.js +18 -18
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +3 -3
- package/dist/db/schema.d.ts +638 -638
- package/dist/db/schema.js +73 -73
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -7
- package/dist/translations/index.d.ts +2 -2
- package/dist/translations/index.js +15 -15
- package/dist/utils/CpanelApi.d.ts +24 -24
- package/dist/utils/CpanelApi.js +64 -64
- package/dist/utils/constants.d.ts +13 -13
- package/dist/utils/constants.js +61 -61
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/utils.d.ts +59 -59
- package/dist/utils/utils.js +132 -132
- package/dist/validators/checkbox.d.ts +3 -3
- package/dist/validators/checkbox.d.ts.map +1 -1
- package/dist/validators/checkbox.js +12 -12
- package/dist/validators/color.d.ts +3 -3
- package/dist/validators/color.d.ts.map +1 -1
- package/dist/validators/color.js +7 -7
- package/dist/validators/date.d.ts +3 -3
- package/dist/validators/date.d.ts.map +1 -1
- package/dist/validators/date.js +5 -5
- package/dist/validators/document.d.ts +3 -3
- package/dist/validators/document.d.ts.map +1 -1
- package/dist/validators/document.js +57 -57
- package/dist/validators/index.d.ts +14 -14
- package/dist/validators/index.d.ts.map +1 -1
- package/dist/validators/index.js +14 -14
- package/dist/validators/map.d.ts +3 -3
- package/dist/validators/map.d.ts.map +1 -1
- package/dist/validators/map.js +5 -5
- package/dist/validators/number.d.ts +3 -3
- package/dist/validators/number.d.ts.map +1 -1
- package/dist/validators/number.js +20 -20
- package/dist/validators/password.d.ts +3 -3
- package/dist/validators/password.d.ts.map +1 -1
- package/dist/validators/password.js +11 -11
- package/dist/validators/photo.d.ts +3 -3
- package/dist/validators/photo.d.ts.map +1 -1
- package/dist/validators/photo.js +100 -100
- package/dist/validators/richText.d.ts +3 -3
- package/dist/validators/richText.d.ts.map +1 -1
- package/dist/validators/richText.js +8 -8
- package/dist/validators/select-multiple.d.ts +9 -9
- package/dist/validators/select-multiple.d.ts.map +1 -1
- package/dist/validators/select-multiple.js +20 -20
- package/dist/validators/select.d.ts +3 -3
- package/dist/validators/select.d.ts.map +1 -1
- package/dist/validators/select.js +5 -5
- package/dist/validators/text.d.ts +3 -3
- package/dist/validators/text.d.ts.map +1 -1
- package/dist/validators/text.js +7 -7
- package/dist/validators/textarea.d.ts +3 -3
- package/dist/validators/textarea.d.ts.map +1 -1
- package/dist/validators/textarea.js +7 -7
- package/dist/validators/video.d.ts +3 -3
- package/dist/validators/video.d.ts.map +1 -1
- package/dist/validators/video.js +57 -57
- package/package.json +2 -3
package/dist/auth/react.js
CHANGED
|
@@ -1,347 +1,347 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module react
|
|
3
|
-
*/
|
|
4
|
-
'use client';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import { fetchData, now, useOnline } from
|
|
7
|
-
import { useRouter } from 'next/navigation';
|
|
8
|
-
import useAxiosPrivate from
|
|
9
|
-
import useRefreshToken from
|
|
10
|
-
export const __AUTH = {
|
|
11
|
-
_lastSync: 0,
|
|
12
|
-
_session: undefined,
|
|
13
|
-
_getSession: () => { },
|
|
14
|
-
};
|
|
15
|
-
export async function logout(options) {
|
|
16
|
-
const { deleteCookies = true } = options ?? {};
|
|
17
|
-
if (deleteCookies) {
|
|
18
|
-
/**
|
|
19
|
-
* Send a request to the server to remove the session.
|
|
20
|
-
* This will delete the cookies.
|
|
21
|
-
* It will also delete the session from the database if auth() is not null.
|
|
22
|
-
*/
|
|
23
|
-
await fetch('/api/auth', {
|
|
24
|
-
method: 'DELETE',
|
|
25
|
-
headers: {
|
|
26
|
-
'Content-Type': 'application/json',
|
|
27
|
-
'x-csrf-token': await getCsrfToken(),
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Broadcast a message to all other tabs/windows to tell them the user has logged out.
|
|
33
|
-
* This is to ensure all tabs/windows trigger a session update.
|
|
34
|
-
*/
|
|
35
|
-
broadcast().postMessage({ event: 'session', data: { trigger: 'logout' } });
|
|
36
|
-
/**
|
|
37
|
-
* Remove the session in the current tab/window.
|
|
38
|
-
*/
|
|
39
|
-
await __AUTH._getSession({ event: 'logout' });
|
|
40
|
-
}
|
|
41
|
-
export async function login({ username, password }) {
|
|
42
|
-
const response = await fetch('/api/auth', {
|
|
43
|
-
method: 'POST',
|
|
44
|
-
headers: {
|
|
45
|
-
'Content-Type': 'application/json',
|
|
46
|
-
'x-csrf-token': await getCsrfToken(),
|
|
47
|
-
},
|
|
48
|
-
body: JSON.stringify({ username, password }),
|
|
49
|
-
});
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
const error = await response.json();
|
|
52
|
-
throw new Error(error.error);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Broadcast a message to all other tabs/windows to tell them the user has logged in.
|
|
56
|
-
* This is to ensure all tabs/windows trigger a session update.
|
|
57
|
-
*/
|
|
58
|
-
broadcast().postMessage({ event: 'session', data: { trigger: 'login' } });
|
|
59
|
-
/**
|
|
60
|
-
* Update the session in the current tab/window.
|
|
61
|
-
*/
|
|
62
|
-
await __AUTH._getSession({ event: 'storage' });
|
|
63
|
-
}
|
|
64
|
-
export async function refreshSession() {
|
|
65
|
-
/**
|
|
66
|
-
* Broadcast a message to all other tabs/windows to tell them the session has been updated.
|
|
67
|
-
* This is to ensure all tabs/windows trigger a session update.
|
|
68
|
-
*/
|
|
69
|
-
broadcast().postMessage({ event: 'session', data: { trigger: 'refresh' } });
|
|
70
|
-
/**
|
|
71
|
-
* Update the session in the current tab/window.
|
|
72
|
-
*/
|
|
73
|
-
await __AUTH._getSession({ event: 'storage' });
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Returns the current CSRF token.
|
|
77
|
-
* required to make requests that changes state.
|
|
78
|
-
*
|
|
79
|
-
* [CSRF Prevention: Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)
|
|
80
|
-
*/
|
|
81
|
-
export async function getCsrfToken() {
|
|
82
|
-
const response = await fetchData('csrf');
|
|
83
|
-
return response?.csrfToken ?? '';
|
|
84
|
-
}
|
|
85
|
-
let broadcastChannel = null;
|
|
86
|
-
function getNewBroadcastChannel() {
|
|
87
|
-
return new BroadcastChannel('lzcms-auth');
|
|
88
|
-
}
|
|
89
|
-
function broadcast() {
|
|
90
|
-
if (typeof BroadcastChannel === 'undefined') {
|
|
91
|
-
return {
|
|
92
|
-
postMessage: () => { },
|
|
93
|
-
addEventListener: () => { },
|
|
94
|
-
removeEventListener: () => { },
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
if (broadcastChannel === null) {
|
|
98
|
-
broadcastChannel = getNewBroadcastChannel();
|
|
99
|
-
}
|
|
100
|
-
return broadcastChannel;
|
|
101
|
-
}
|
|
102
|
-
export async function getSession(params) {
|
|
103
|
-
const session = await fetchData('session', params);
|
|
104
|
-
if (params?.broadcast ?? true) {
|
|
105
|
-
const broadcastChannel = getNewBroadcastChannel();
|
|
106
|
-
broadcastChannel.postMessage({
|
|
107
|
-
event: 'session',
|
|
108
|
-
data: { trigger: 'getSession' },
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return session;
|
|
112
|
-
}
|
|
113
|
-
export const SessionContext = React.createContext?.(undefined);
|
|
114
|
-
export function useSession(options) {
|
|
115
|
-
const router = useRouter();
|
|
116
|
-
if (!SessionContext) {
|
|
117
|
-
throw new Error('React Context is unavailable in Server Components');
|
|
118
|
-
}
|
|
119
|
-
// @ts-expect-error Satisfy TS if branch on line below
|
|
120
|
-
const value = React.useContext(SessionContext);
|
|
121
|
-
if (!value && process.env.NODE_ENV !== 'production') {
|
|
122
|
-
throw new Error('[next-auth]: `useSession` must be wrapped in a <SessionProvider />');
|
|
123
|
-
}
|
|
124
|
-
const { required, onUnauthenticated } = options ?? {};
|
|
125
|
-
const requiredAndNotLoading = required && value.status === 'unauthenticated';
|
|
126
|
-
React.useEffect(() => {
|
|
127
|
-
if (requiredAndNotLoading) {
|
|
128
|
-
const url = `/auth/login?${new URLSearchParams({
|
|
129
|
-
callbackUrl: window.location.href,
|
|
130
|
-
})}`;
|
|
131
|
-
if (onUnauthenticated)
|
|
132
|
-
onUnauthenticated();
|
|
133
|
-
else
|
|
134
|
-
router.push(url);
|
|
135
|
-
}
|
|
136
|
-
}, [requiredAndNotLoading, onUnauthenticated]);
|
|
137
|
-
if (requiredAndNotLoading) {
|
|
138
|
-
return {
|
|
139
|
-
data: value.data,
|
|
140
|
-
update: value.update,
|
|
141
|
-
status: 'loading',
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
return value;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* [React Context](https://react.dev/learn/passing-data-deeply-with-context) provider to wrap the app (`pages/`) to make session data available anywhere.
|
|
148
|
-
*
|
|
149
|
-
* When used, the session state is automatically synchronized across all open tabs/windows and they are all updated whenever they gain or lose focus
|
|
150
|
-
* or the state changes (e.g. a user signs in or out) when {@link SessionProviderProps.refetchOnWindowFocus} is `true`.
|
|
151
|
-
*
|
|
152
|
-
* :::info
|
|
153
|
-
* `SessionProvider` is for client-side use only and when using [Next.js App Router (`app/`)](https://nextjs.org/blog/next-13-4#nextjs-app-router) you should prefer the `auth()` export.
|
|
154
|
-
* :::
|
|
155
|
-
*/
|
|
156
|
-
export function SessionProvider(props) {
|
|
157
|
-
if (!SessionContext) {
|
|
158
|
-
throw new Error('React Context is unavailable in Server Components');
|
|
159
|
-
}
|
|
160
|
-
const axiosPrivate = useAxiosPrivate({
|
|
161
|
-
refreshTokenOn: 404,
|
|
162
|
-
});
|
|
163
|
-
const { children, refetchInterval, refetchWhenOffline } = props;
|
|
164
|
-
/**
|
|
165
|
-
* If session was `null`, there was an attempt to fetch it,
|
|
166
|
-
* but it failed, but we still treat it as a valid initial value.
|
|
167
|
-
*/
|
|
168
|
-
const hasInitialSession = props.session !== undefined;
|
|
169
|
-
/** If session was passed, initialize as already synced */
|
|
170
|
-
__AUTH._lastSync = hasInitialSession ? now() : 0;
|
|
171
|
-
const [session, setSession] = React.useState(() => {
|
|
172
|
-
if (hasInitialSession)
|
|
173
|
-
__AUTH._session = props.session;
|
|
174
|
-
return props.session;
|
|
175
|
-
});
|
|
176
|
-
/** If session was passed, initialize as not loading */
|
|
177
|
-
const [loading, setLoading] = React.useState(!hasInitialSession);
|
|
178
|
-
React.useEffect(() => {
|
|
179
|
-
async function generateInitialSession() {
|
|
180
|
-
/**
|
|
181
|
-
* Use the `axiosPrivate` instance to make a request to `/api/auth/session` to get the
|
|
182
|
-
* first session data. The reason for using `axiosPrivate` is to make sure that the client
|
|
183
|
-
* will initiate a refresh token process (with the refresh token cookie) if the access
|
|
184
|
-
* token cookie is expired. (TRPC custom refresh link can be used as well)
|
|
185
|
-
*/
|
|
186
|
-
try {
|
|
187
|
-
const response = await axiosPrivate.get('/auth/session');
|
|
188
|
-
return response.data;
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async function init() {
|
|
195
|
-
/**
|
|
196
|
-
* Make sure the session is created at the start of the app.
|
|
197
|
-
* Is session is not set, this means this is the first time
|
|
198
|
-
* the app is being loaded.
|
|
199
|
-
*/
|
|
200
|
-
if (__AUTH._session === undefined) {
|
|
201
|
-
const session = await generateInitialSession();
|
|
202
|
-
__AUTH._lastSync = now();
|
|
203
|
-
return session;
|
|
204
|
-
}
|
|
205
|
-
return __AUTH._session;
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Initialize the session.
|
|
209
|
-
*/
|
|
210
|
-
init()
|
|
211
|
-
.then(async (session) => {
|
|
212
|
-
if (session) {
|
|
213
|
-
__AUTH._session = session;
|
|
214
|
-
setSession(session);
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
/**
|
|
218
|
-
* It's not necessary to log out the user and broadcast the logout event,
|
|
219
|
-
* because there are no cookies set to delete.
|
|
220
|
-
* But it's a good practice to do so.
|
|
221
|
-
*/
|
|
222
|
-
// await logout()
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
.then(() => {
|
|
226
|
-
__AUTH._getSession = async ({ event } = {}) => {
|
|
227
|
-
try {
|
|
228
|
-
/**
|
|
229
|
-
* If the event is a logout event, we should clear the session and return early.
|
|
230
|
-
*/
|
|
231
|
-
if (event === 'logout') {
|
|
232
|
-
__AUTH._lastSync = now();
|
|
233
|
-
__AUTH._session = null;
|
|
234
|
-
setSession(null);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* If the event is a storage event, we should update the session and not broadcast the event.
|
|
239
|
-
* Storage events can also be triggered when a broadcast message is sent from another
|
|
240
|
-
* tab/window. (see below)
|
|
241
|
-
*/
|
|
242
|
-
if (event === 'storage') {
|
|
243
|
-
__AUTH._lastSync = now();
|
|
244
|
-
__AUTH._session = await getSession({
|
|
245
|
-
broadcast: false,
|
|
246
|
-
});
|
|
247
|
-
setSession(__AUTH._session);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
if (
|
|
251
|
-
// If there is no time defined for when a session should be considered
|
|
252
|
-
// stale, then it's okay to use the value we have until an event is
|
|
253
|
-
// triggered which updates it
|
|
254
|
-
!event ||
|
|
255
|
-
// If the client doesn't have a session then we don't need to call
|
|
256
|
-
// the server to check if it does (if they have signed in via another
|
|
257
|
-
// tab or window that will come through as a "storage" event anyway)
|
|
258
|
-
__AUTH._session === null ||
|
|
259
|
-
// Bail out early if the client session is not stale yet
|
|
260
|
-
now() < __AUTH._lastSync) {
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
// An event or session staleness occurred, update the client session.
|
|
264
|
-
__AUTH._lastSync = now();
|
|
265
|
-
__AUTH._session = await getSession();
|
|
266
|
-
setSession(__AUTH._session);
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
__AUTH._lastSync = now();
|
|
270
|
-
__AUTH._session = null;
|
|
271
|
-
setSession(null);
|
|
272
|
-
// console.error('Error fetching session', error)
|
|
273
|
-
}
|
|
274
|
-
finally {
|
|
275
|
-
setLoading(false);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
})
|
|
279
|
-
.finally(() => setLoading(false));
|
|
280
|
-
return () => {
|
|
281
|
-
__AUTH._lastSync = 0;
|
|
282
|
-
__AUTH._session = undefined;
|
|
283
|
-
__AUTH._getSession = () => { };
|
|
284
|
-
};
|
|
285
|
-
}, []);
|
|
286
|
-
React.useEffect(() => {
|
|
287
|
-
const handle = () => __AUTH._getSession({ event: 'storage' });
|
|
288
|
-
// Listen for storage events and update session if event fired from
|
|
289
|
-
// another window (but suppress firing another event to avoid a loop)
|
|
290
|
-
// Fetch new session data but tell it not to fire another event to
|
|
291
|
-
// avoid an infinite loop.
|
|
292
|
-
// Note: We could pass session data through and do something like
|
|
293
|
-
// `setData(message.data)` but that can cause problems depending
|
|
294
|
-
// on how the session object is being used in the client; it is
|
|
295
|
-
// more robust to have each window/tab fetch it's own copy of the
|
|
296
|
-
// session object rather than share it across instances.
|
|
297
|
-
broadcast().addEventListener('message', handle);
|
|
298
|
-
return () => broadcast().removeEventListener('message', handle);
|
|
299
|
-
}, []);
|
|
300
|
-
React.useEffect(() => {
|
|
301
|
-
const { refetchOnWindowFocus = true } = props;
|
|
302
|
-
// Listen for when the page is visible, if the user switches tabs
|
|
303
|
-
// and makes our tab visible again, re-fetch the session, but only if
|
|
304
|
-
// this feature is not disabled.
|
|
305
|
-
const visibilityHandler = () => {
|
|
306
|
-
if (refetchOnWindowFocus && document.visibilityState === 'visible')
|
|
307
|
-
__AUTH._getSession({ event: 'visibilitychange' });
|
|
308
|
-
};
|
|
309
|
-
document.addEventListener('visibilitychange', visibilityHandler, false);
|
|
310
|
-
return () => document.removeEventListener('visibilitychange', visibilityHandler, false);
|
|
311
|
-
}, [props.refetchOnWindowFocus]);
|
|
312
|
-
const isOnline = useOnline();
|
|
313
|
-
// TODO: Flip this behavior in next major version
|
|
314
|
-
const shouldRefetch = refetchWhenOffline !== false || isOnline;
|
|
315
|
-
React.useEffect(() => {
|
|
316
|
-
if (refetchInterval && shouldRefetch) {
|
|
317
|
-
const refetchIntervalTimer = setInterval(() => {
|
|
318
|
-
if (__AUTH._session) {
|
|
319
|
-
__AUTH._getSession({ event: 'poll' });
|
|
320
|
-
}
|
|
321
|
-
}, refetchInterval * 1000);
|
|
322
|
-
return () => clearInterval(refetchIntervalTimer);
|
|
323
|
-
}
|
|
324
|
-
}, [refetchInterval, shouldRefetch]);
|
|
325
|
-
const value = React.useMemo(() => ({
|
|
326
|
-
data: session,
|
|
327
|
-
status: loading ? 'loading' : session ? 'authenticated' : 'unauthenticated',
|
|
328
|
-
async update(data) {
|
|
329
|
-
if (loading)
|
|
330
|
-
return;
|
|
331
|
-
setLoading(true);
|
|
332
|
-
const newSession = await fetchData('session', typeof data === 'undefined' ? undefined : { body: { data } });
|
|
333
|
-
setLoading(false);
|
|
334
|
-
if (newSession) {
|
|
335
|
-
setSession(newSession);
|
|
336
|
-
broadcast().postMessage({
|
|
337
|
-
event: 'session',
|
|
338
|
-
data: { trigger: 'getSession' },
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
return newSession;
|
|
342
|
-
},
|
|
343
|
-
}), [session, loading]);
|
|
344
|
-
return React.createElement(SessionContext.Provider, { value: value }, children);
|
|
345
|
-
}
|
|
346
|
-
export { useAxiosPrivate, useRefreshToken };
|
|
347
|
-
export { refreshTokenLink } from
|
|
1
|
+
/**
|
|
2
|
+
* @module react
|
|
3
|
+
*/
|
|
4
|
+
'use client';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { fetchData, now, useOnline } from './lib/client.jsx';
|
|
7
|
+
import { useRouter } from 'next/navigation';
|
|
8
|
+
import useAxiosPrivate from './hooks/useAxiosPrivate.jsx';
|
|
9
|
+
import useRefreshToken from './hooks/useRefreshToken.jsx';
|
|
10
|
+
export const __AUTH = {
|
|
11
|
+
_lastSync: 0,
|
|
12
|
+
_session: undefined,
|
|
13
|
+
_getSession: () => { },
|
|
14
|
+
};
|
|
15
|
+
export async function logout(options) {
|
|
16
|
+
const { deleteCookies = true } = options ?? {};
|
|
17
|
+
if (deleteCookies) {
|
|
18
|
+
/**
|
|
19
|
+
* Send a request to the server to remove the session.
|
|
20
|
+
* This will delete the cookies.
|
|
21
|
+
* It will also delete the session from the database if auth() is not null.
|
|
22
|
+
*/
|
|
23
|
+
await fetch('/api/auth', {
|
|
24
|
+
method: 'DELETE',
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type': 'application/json',
|
|
27
|
+
'x-csrf-token': await getCsrfToken(),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Broadcast a message to all other tabs/windows to tell them the user has logged out.
|
|
33
|
+
* This is to ensure all tabs/windows trigger a session update.
|
|
34
|
+
*/
|
|
35
|
+
broadcast().postMessage({ event: 'session', data: { trigger: 'logout' } });
|
|
36
|
+
/**
|
|
37
|
+
* Remove the session in the current tab/window.
|
|
38
|
+
*/
|
|
39
|
+
await __AUTH._getSession({ event: 'logout' });
|
|
40
|
+
}
|
|
41
|
+
export async function login({ username, password }) {
|
|
42
|
+
const response = await fetch('/api/auth', {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
'x-csrf-token': await getCsrfToken(),
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify({ username, password }),
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
const error = await response.json();
|
|
52
|
+
throw new Error(error.error);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Broadcast a message to all other tabs/windows to tell them the user has logged in.
|
|
56
|
+
* This is to ensure all tabs/windows trigger a session update.
|
|
57
|
+
*/
|
|
58
|
+
broadcast().postMessage({ event: 'session', data: { trigger: 'login' } });
|
|
59
|
+
/**
|
|
60
|
+
* Update the session in the current tab/window.
|
|
61
|
+
*/
|
|
62
|
+
await __AUTH._getSession({ event: 'storage' });
|
|
63
|
+
}
|
|
64
|
+
export async function refreshSession() {
|
|
65
|
+
/**
|
|
66
|
+
* Broadcast a message to all other tabs/windows to tell them the session has been updated.
|
|
67
|
+
* This is to ensure all tabs/windows trigger a session update.
|
|
68
|
+
*/
|
|
69
|
+
broadcast().postMessage({ event: 'session', data: { trigger: 'refresh' } });
|
|
70
|
+
/**
|
|
71
|
+
* Update the session in the current tab/window.
|
|
72
|
+
*/
|
|
73
|
+
await __AUTH._getSession({ event: 'storage' });
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the current CSRF token.
|
|
77
|
+
* required to make requests that changes state.
|
|
78
|
+
*
|
|
79
|
+
* [CSRF Prevention: Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)
|
|
80
|
+
*/
|
|
81
|
+
export async function getCsrfToken() {
|
|
82
|
+
const response = await fetchData('csrf');
|
|
83
|
+
return response?.csrfToken ?? '';
|
|
84
|
+
}
|
|
85
|
+
let broadcastChannel = null;
|
|
86
|
+
function getNewBroadcastChannel() {
|
|
87
|
+
return new BroadcastChannel('lzcms-auth');
|
|
88
|
+
}
|
|
89
|
+
function broadcast() {
|
|
90
|
+
if (typeof BroadcastChannel === 'undefined') {
|
|
91
|
+
return {
|
|
92
|
+
postMessage: () => { },
|
|
93
|
+
addEventListener: () => { },
|
|
94
|
+
removeEventListener: () => { },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (broadcastChannel === null) {
|
|
98
|
+
broadcastChannel = getNewBroadcastChannel();
|
|
99
|
+
}
|
|
100
|
+
return broadcastChannel;
|
|
101
|
+
}
|
|
102
|
+
export async function getSession(params) {
|
|
103
|
+
const session = await fetchData('session', params);
|
|
104
|
+
if (params?.broadcast ?? true) {
|
|
105
|
+
const broadcastChannel = getNewBroadcastChannel();
|
|
106
|
+
broadcastChannel.postMessage({
|
|
107
|
+
event: 'session',
|
|
108
|
+
data: { trigger: 'getSession' },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return session;
|
|
112
|
+
}
|
|
113
|
+
export const SessionContext = React.createContext?.(undefined);
|
|
114
|
+
export function useSession(options) {
|
|
115
|
+
const router = useRouter();
|
|
116
|
+
if (!SessionContext) {
|
|
117
|
+
throw new Error('React Context is unavailable in Server Components');
|
|
118
|
+
}
|
|
119
|
+
// @ts-expect-error Satisfy TS if branch on line below
|
|
120
|
+
const value = React.useContext(SessionContext);
|
|
121
|
+
if (!value && process.env.NODE_ENV !== 'production') {
|
|
122
|
+
throw new Error('[next-auth]: `useSession` must be wrapped in a <SessionProvider />');
|
|
123
|
+
}
|
|
124
|
+
const { required, onUnauthenticated } = options ?? {};
|
|
125
|
+
const requiredAndNotLoading = required && value.status === 'unauthenticated';
|
|
126
|
+
React.useEffect(() => {
|
|
127
|
+
if (requiredAndNotLoading) {
|
|
128
|
+
const url = `/auth/login?${new URLSearchParams({
|
|
129
|
+
callbackUrl: window.location.href,
|
|
130
|
+
})}`;
|
|
131
|
+
if (onUnauthenticated)
|
|
132
|
+
onUnauthenticated();
|
|
133
|
+
else
|
|
134
|
+
router.push(url);
|
|
135
|
+
}
|
|
136
|
+
}, [requiredAndNotLoading, onUnauthenticated]);
|
|
137
|
+
if (requiredAndNotLoading) {
|
|
138
|
+
return {
|
|
139
|
+
data: value.data,
|
|
140
|
+
update: value.update,
|
|
141
|
+
status: 'loading',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* [React Context](https://react.dev/learn/passing-data-deeply-with-context) provider to wrap the app (`pages/`) to make session data available anywhere.
|
|
148
|
+
*
|
|
149
|
+
* When used, the session state is automatically synchronized across all open tabs/windows and they are all updated whenever they gain or lose focus
|
|
150
|
+
* or the state changes (e.g. a user signs in or out) when {@link SessionProviderProps.refetchOnWindowFocus} is `true`.
|
|
151
|
+
*
|
|
152
|
+
* :::info
|
|
153
|
+
* `SessionProvider` is for client-side use only and when using [Next.js App Router (`app/`)](https://nextjs.org/blog/next-13-4#nextjs-app-router) you should prefer the `auth()` export.
|
|
154
|
+
* :::
|
|
155
|
+
*/
|
|
156
|
+
export function SessionProvider(props) {
|
|
157
|
+
if (!SessionContext) {
|
|
158
|
+
throw new Error('React Context is unavailable in Server Components');
|
|
159
|
+
}
|
|
160
|
+
const axiosPrivate = useAxiosPrivate({
|
|
161
|
+
refreshTokenOn: 404,
|
|
162
|
+
});
|
|
163
|
+
const { children, refetchInterval, refetchWhenOffline } = props;
|
|
164
|
+
/**
|
|
165
|
+
* If session was `null`, there was an attempt to fetch it,
|
|
166
|
+
* but it failed, but we still treat it as a valid initial value.
|
|
167
|
+
*/
|
|
168
|
+
const hasInitialSession = props.session !== undefined;
|
|
169
|
+
/** If session was passed, initialize as already synced */
|
|
170
|
+
__AUTH._lastSync = hasInitialSession ? now() : 0;
|
|
171
|
+
const [session, setSession] = React.useState(() => {
|
|
172
|
+
if (hasInitialSession)
|
|
173
|
+
__AUTH._session = props.session;
|
|
174
|
+
return props.session;
|
|
175
|
+
});
|
|
176
|
+
/** If session was passed, initialize as not loading */
|
|
177
|
+
const [loading, setLoading] = React.useState(!hasInitialSession);
|
|
178
|
+
React.useEffect(() => {
|
|
179
|
+
async function generateInitialSession() {
|
|
180
|
+
/**
|
|
181
|
+
* Use the `axiosPrivate` instance to make a request to `/api/auth/session` to get the
|
|
182
|
+
* first session data. The reason for using `axiosPrivate` is to make sure that the client
|
|
183
|
+
* will initiate a refresh token process (with the refresh token cookie) if the access
|
|
184
|
+
* token cookie is expired. (TRPC custom refresh link can be used as well)
|
|
185
|
+
*/
|
|
186
|
+
try {
|
|
187
|
+
const response = await axiosPrivate.get('/auth/session');
|
|
188
|
+
return response.data;
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function init() {
|
|
195
|
+
/**
|
|
196
|
+
* Make sure the session is created at the start of the app.
|
|
197
|
+
* Is session is not set, this means this is the first time
|
|
198
|
+
* the app is being loaded.
|
|
199
|
+
*/
|
|
200
|
+
if (__AUTH._session === undefined) {
|
|
201
|
+
const session = await generateInitialSession();
|
|
202
|
+
__AUTH._lastSync = now();
|
|
203
|
+
return session;
|
|
204
|
+
}
|
|
205
|
+
return __AUTH._session;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Initialize the session.
|
|
209
|
+
*/
|
|
210
|
+
init()
|
|
211
|
+
.then(async (session) => {
|
|
212
|
+
if (session) {
|
|
213
|
+
__AUTH._session = session;
|
|
214
|
+
setSession(session);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
/**
|
|
218
|
+
* It's not necessary to log out the user and broadcast the logout event,
|
|
219
|
+
* because there are no cookies set to delete.
|
|
220
|
+
* But it's a good practice to do so.
|
|
221
|
+
*/
|
|
222
|
+
// await logout()
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
.then(() => {
|
|
226
|
+
__AUTH._getSession = async ({ event } = {}) => {
|
|
227
|
+
try {
|
|
228
|
+
/**
|
|
229
|
+
* If the event is a logout event, we should clear the session and return early.
|
|
230
|
+
*/
|
|
231
|
+
if (event === 'logout') {
|
|
232
|
+
__AUTH._lastSync = now();
|
|
233
|
+
__AUTH._session = null;
|
|
234
|
+
setSession(null);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* If the event is a storage event, we should update the session and not broadcast the event.
|
|
239
|
+
* Storage events can also be triggered when a broadcast message is sent from another
|
|
240
|
+
* tab/window. (see below)
|
|
241
|
+
*/
|
|
242
|
+
if (event === 'storage') {
|
|
243
|
+
__AUTH._lastSync = now();
|
|
244
|
+
__AUTH._session = await getSession({
|
|
245
|
+
broadcast: false,
|
|
246
|
+
});
|
|
247
|
+
setSession(__AUTH._session);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (
|
|
251
|
+
// If there is no time defined for when a session should be considered
|
|
252
|
+
// stale, then it's okay to use the value we have until an event is
|
|
253
|
+
// triggered which updates it
|
|
254
|
+
!event ||
|
|
255
|
+
// If the client doesn't have a session then we don't need to call
|
|
256
|
+
// the server to check if it does (if they have signed in via another
|
|
257
|
+
// tab or window that will come through as a "storage" event anyway)
|
|
258
|
+
__AUTH._session === null ||
|
|
259
|
+
// Bail out early if the client session is not stale yet
|
|
260
|
+
now() < __AUTH._lastSync) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// An event or session staleness occurred, update the client session.
|
|
264
|
+
__AUTH._lastSync = now();
|
|
265
|
+
__AUTH._session = await getSession();
|
|
266
|
+
setSession(__AUTH._session);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
__AUTH._lastSync = now();
|
|
270
|
+
__AUTH._session = null;
|
|
271
|
+
setSession(null);
|
|
272
|
+
// console.error('Error fetching session', error)
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
setLoading(false);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
})
|
|
279
|
+
.finally(() => setLoading(false));
|
|
280
|
+
return () => {
|
|
281
|
+
__AUTH._lastSync = 0;
|
|
282
|
+
__AUTH._session = undefined;
|
|
283
|
+
__AUTH._getSession = () => { };
|
|
284
|
+
};
|
|
285
|
+
}, []);
|
|
286
|
+
React.useEffect(() => {
|
|
287
|
+
const handle = () => __AUTH._getSession({ event: 'storage' });
|
|
288
|
+
// Listen for storage events and update session if event fired from
|
|
289
|
+
// another window (but suppress firing another event to avoid a loop)
|
|
290
|
+
// Fetch new session data but tell it not to fire another event to
|
|
291
|
+
// avoid an infinite loop.
|
|
292
|
+
// Note: We could pass session data through and do something like
|
|
293
|
+
// `setData(message.data)` but that can cause problems depending
|
|
294
|
+
// on how the session object is being used in the client; it is
|
|
295
|
+
// more robust to have each window/tab fetch it's own copy of the
|
|
296
|
+
// session object rather than share it across instances.
|
|
297
|
+
broadcast().addEventListener('message', handle);
|
|
298
|
+
return () => broadcast().removeEventListener('message', handle);
|
|
299
|
+
}, []);
|
|
300
|
+
React.useEffect(() => {
|
|
301
|
+
const { refetchOnWindowFocus = true } = props;
|
|
302
|
+
// Listen for when the page is visible, if the user switches tabs
|
|
303
|
+
// and makes our tab visible again, re-fetch the session, but only if
|
|
304
|
+
// this feature is not disabled.
|
|
305
|
+
const visibilityHandler = () => {
|
|
306
|
+
if (refetchOnWindowFocus && document.visibilityState === 'visible')
|
|
307
|
+
__AUTH._getSession({ event: 'visibilitychange' });
|
|
308
|
+
};
|
|
309
|
+
document.addEventListener('visibilitychange', visibilityHandler, false);
|
|
310
|
+
return () => document.removeEventListener('visibilitychange', visibilityHandler, false);
|
|
311
|
+
}, [props.refetchOnWindowFocus]);
|
|
312
|
+
const isOnline = useOnline();
|
|
313
|
+
// TODO: Flip this behavior in next major version
|
|
314
|
+
const shouldRefetch = refetchWhenOffline !== false || isOnline;
|
|
315
|
+
React.useEffect(() => {
|
|
316
|
+
if (refetchInterval && shouldRefetch) {
|
|
317
|
+
const refetchIntervalTimer = setInterval(() => {
|
|
318
|
+
if (__AUTH._session) {
|
|
319
|
+
__AUTH._getSession({ event: 'poll' });
|
|
320
|
+
}
|
|
321
|
+
}, refetchInterval * 1000);
|
|
322
|
+
return () => clearInterval(refetchIntervalTimer);
|
|
323
|
+
}
|
|
324
|
+
}, [refetchInterval, shouldRefetch]);
|
|
325
|
+
const value = React.useMemo(() => ({
|
|
326
|
+
data: session,
|
|
327
|
+
status: loading ? 'loading' : session ? 'authenticated' : 'unauthenticated',
|
|
328
|
+
async update(data) {
|
|
329
|
+
if (loading)
|
|
330
|
+
return;
|
|
331
|
+
setLoading(true);
|
|
332
|
+
const newSession = await fetchData('session', typeof data === 'undefined' ? undefined : { body: { data } });
|
|
333
|
+
setLoading(false);
|
|
334
|
+
if (newSession) {
|
|
335
|
+
setSession(newSession);
|
|
336
|
+
broadcast().postMessage({
|
|
337
|
+
event: 'session',
|
|
338
|
+
data: { trigger: 'getSession' },
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return newSession;
|
|
342
|
+
},
|
|
343
|
+
}), [session, loading]);
|
|
344
|
+
return React.createElement(SessionContext.Provider, { value: value }, children);
|
|
345
|
+
}
|
|
346
|
+
export { useAxiosPrivate, useRefreshToken };
|
|
347
|
+
export { refreshTokenLink } from './trpc';
|