nextjs-cms 0.5.9 → 0.5.11

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.
Files changed (258) hide show
  1. package/dist/api/axios/axiosInstance.d.ts +1 -1
  2. package/dist/api/axios/axiosInstance.js +8 -8
  3. package/dist/api/index.d.ts +855 -855
  4. package/dist/api/index.d.ts.map +1 -1
  5. package/dist/api/index.js +12 -12
  6. package/dist/api/lib/serverActions.d.ts +239 -239
  7. package/dist/api/lib/serverActions.d.ts.map +1 -1
  8. package/dist/api/lib/serverActions.js +834 -834
  9. package/dist/api/root.d.ts +828 -828
  10. package/dist/api/root.js +30 -30
  11. package/dist/api/routers/accountSettings.d.ts +60 -60
  12. package/dist/api/routers/accountSettings.js +108 -108
  13. package/dist/api/routers/admins.d.ts +105 -105
  14. package/dist/api/routers/admins.js +219 -219
  15. package/dist/api/routers/auth.d.ts +47 -47
  16. package/dist/api/routers/auth.js +25 -25
  17. package/dist/api/routers/categorySection.d.ts +103 -103
  18. package/dist/api/routers/categorySection.js +38 -38
  19. package/dist/api/routers/cmsSettings.d.ts +48 -48
  20. package/dist/api/routers/cmsSettings.js +51 -51
  21. package/dist/api/routers/cpanel.d.ts +83 -83
  22. package/dist/api/routers/cpanel.js +216 -216
  23. package/dist/api/routers/files.d.ts +47 -47
  24. package/dist/api/routers/files.js +23 -23
  25. package/dist/api/routers/gallery.d.ts +35 -35
  26. package/dist/api/routers/gallery.js +62 -62
  27. package/dist/api/routers/googleAnalytics.d.ts +30 -30
  28. package/dist/api/routers/googleAnalytics.js +7 -7
  29. package/dist/api/routers/hasItemsSection.d.ts +139 -139
  30. package/dist/api/routers/hasItemsSection.js +34 -34
  31. package/dist/api/routers/navigation.d.ts +51 -51
  32. package/dist/api/routers/navigation.js +11 -11
  33. package/dist/api/routers/simpleSection.d.ts +57 -57
  34. package/dist/api/routers/simpleSection.js +12 -12
  35. package/dist/api/trpc.d.ts +106 -106
  36. package/dist/api/trpc.js +72 -72
  37. package/dist/auth/axios/axiosInstance.d.ts +1 -1
  38. package/dist/auth/axios/axiosInstance.js +8 -8
  39. package/dist/auth/csrf.d.ts +29 -29
  40. package/dist/auth/csrf.js +76 -76
  41. package/dist/auth/hooks/index.d.ts +3 -3
  42. package/dist/auth/hooks/index.d.ts.map +1 -1
  43. package/dist/auth/hooks/index.js +3 -3
  44. package/dist/auth/hooks/useAxiosPrivate.d.ts +4 -4
  45. package/dist/auth/hooks/useAxiosPrivate.js +74 -74
  46. package/dist/auth/hooks/useRefreshToken.d.ts +6 -6
  47. package/dist/auth/hooks/useRefreshToken.js +79 -79
  48. package/dist/auth/index.d.ts +22 -22
  49. package/dist/auth/index.js +44 -44
  50. package/dist/auth/jwt.d.ts +5 -5
  51. package/dist/auth/jwt.js +25 -25
  52. package/dist/auth/lib/actions.d.ts +32 -32
  53. package/dist/auth/lib/actions.d.ts.map +1 -1
  54. package/dist/auth/lib/actions.js +209 -209
  55. package/dist/auth/lib/client.d.ts +3 -3
  56. package/dist/auth/lib/client.js +46 -46
  57. package/dist/auth/lib/index.d.ts +2 -2
  58. package/dist/auth/lib/index.d.ts.map +1 -1
  59. package/dist/auth/lib/index.js +2 -2
  60. package/dist/auth/react.d.ts +105 -105
  61. package/dist/auth/react.d.ts.map +1 -1
  62. package/dist/auth/react.js +347 -347
  63. package/dist/auth/trpc.d.ts +5 -5
  64. package/dist/auth/trpc.d.ts.map +1 -1
  65. package/dist/auth/trpc.js +81 -81
  66. package/dist/core/config/config-loader.d.ts +91 -91
  67. package/dist/core/config/config-loader.js +230 -230
  68. package/dist/core/config/index.d.ts +2 -2
  69. package/dist/core/config/index.d.ts.map +1 -1
  70. package/dist/core/config/index.js +1 -1
  71. package/dist/core/config/loader.d.ts +1 -1
  72. package/dist/core/config/loader.js +42 -42
  73. package/dist/core/db/index.d.ts +1 -1
  74. package/dist/core/db/index.d.ts.map +1 -1
  75. package/dist/core/db/index.js +1 -1
  76. package/dist/core/db/table-checker/DbTable.d.ts +5 -5
  77. package/dist/core/db/table-checker/DbTable.js +5 -5
  78. package/dist/core/db/table-checker/MysqlTable.d.ts +33 -33
  79. package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -1
  80. package/dist/core/db/table-checker/MysqlTable.js +94 -94
  81. package/dist/core/db/table-checker/index.d.ts +1 -1
  82. package/dist/core/db/table-checker/index.d.ts.map +1 -1
  83. package/dist/core/db/table-checker/index.js +1 -1
  84. package/dist/core/factories/FieldFactory.d.ts +123 -123
  85. package/dist/core/factories/FieldFactory.d.ts.map +1 -1
  86. package/dist/core/factories/FieldFactory.js +411 -411
  87. package/dist/core/factories/SectionFactory.d.ts +109 -109
  88. package/dist/core/factories/SectionFactory.d.ts.map +1 -1
  89. package/dist/core/factories/SectionFactory.js +415 -415
  90. package/dist/core/factories/index.d.ts +2 -2
  91. package/dist/core/factories/index.d.ts.map +1 -1
  92. package/dist/core/factories/index.js +2 -2
  93. package/dist/core/fields/checkbox.d.ts +62 -62
  94. package/dist/core/fields/checkbox.d.ts.map +1 -1
  95. package/dist/core/fields/checkbox.js +62 -62
  96. package/dist/core/fields/color.d.ts +83 -83
  97. package/dist/core/fields/color.d.ts.map +1 -1
  98. package/dist/core/fields/color.js +91 -91
  99. package/dist/core/fields/date.d.ts +99 -99
  100. package/dist/core/fields/date.d.ts.map +1 -1
  101. package/dist/core/fields/date.js +108 -108
  102. package/dist/core/fields/document.d.ts +179 -179
  103. package/dist/core/fields/document.d.ts.map +1 -1
  104. package/dist/core/fields/document.js +277 -277
  105. package/dist/core/fields/field-group.d.ts +17 -17
  106. package/dist/core/fields/field-group.d.ts.map +1 -1
  107. package/dist/core/fields/field-group.js +6 -6
  108. package/dist/core/fields/field.d.ts +125 -125
  109. package/dist/core/fields/field.d.ts.map +1 -1
  110. package/dist/core/fields/field.js +148 -148
  111. package/dist/core/fields/fileField.d.ts +14 -14
  112. package/dist/core/fields/fileField.d.ts.map +1 -1
  113. package/dist/core/fields/fileField.js +5 -5
  114. package/dist/core/fields/index.d.ts +64 -64
  115. package/dist/core/fields/index.d.ts.map +1 -1
  116. package/dist/core/fields/index.js +18 -18
  117. package/dist/core/fields/map.d.ts +166 -166
  118. package/dist/core/fields/map.d.ts.map +1 -1
  119. package/dist/core/fields/map.js +152 -152
  120. package/dist/core/fields/number.d.ts +185 -185
  121. package/dist/core/fields/number.d.ts.map +1 -1
  122. package/dist/core/fields/number.js +241 -241
  123. package/dist/core/fields/password.d.ts +108 -108
  124. package/dist/core/fields/password.d.ts.map +1 -1
  125. package/dist/core/fields/password.js +133 -133
  126. package/dist/core/fields/photo.d.ts +288 -288
  127. package/dist/core/fields/photo.d.ts.map +1 -1
  128. package/dist/core/fields/photo.js +410 -410
  129. package/dist/core/fields/richText.d.ts +294 -294
  130. package/dist/core/fields/richText.d.ts.map +1 -1
  131. package/dist/core/fields/richText.js +338 -338
  132. package/dist/core/fields/select.d.ts +365 -365
  133. package/dist/core/fields/select.d.ts.map +1 -1
  134. package/dist/core/fields/select.js +499 -499
  135. package/dist/core/fields/selectMultiple.d.ts +235 -235
  136. package/dist/core/fields/selectMultiple.d.ts.map +1 -1
  137. package/dist/core/fields/selectMultiple.js +417 -417
  138. package/dist/core/fields/tags.d.ts +130 -130
  139. package/dist/core/fields/tags.d.ts.map +1 -1
  140. package/dist/core/fields/tags.js +105 -105
  141. package/dist/core/fields/text.d.ts +135 -135
  142. package/dist/core/fields/text.d.ts.map +1 -1
  143. package/dist/core/fields/text.js +157 -157
  144. package/dist/core/fields/textArea.d.ts +106 -106
  145. package/dist/core/fields/textArea.d.ts.map +1 -1
  146. package/dist/core/fields/textArea.js +126 -126
  147. package/dist/core/fields/video.d.ts +147 -147
  148. package/dist/core/fields/video.d.ts.map +1 -1
  149. package/dist/core/fields/video.js +248 -248
  150. package/dist/core/helpers/entity.d.ts +7 -7
  151. package/dist/core/helpers/entity.js +27 -27
  152. package/dist/core/helpers/index.d.ts +4 -4
  153. package/dist/core/helpers/index.d.ts.map +1 -1
  154. package/dist/core/helpers/index.js +3 -3
  155. package/dist/core/index.d.ts +7 -7
  156. package/dist/core/index.d.ts.map +1 -1
  157. package/dist/core/index.js +7 -7
  158. package/dist/core/sections/category.d.ts +282 -282
  159. package/dist/core/sections/category.d.ts.map +1 -1
  160. package/dist/core/sections/category.js +147 -147
  161. package/dist/core/sections/hasItems.d.ts +631 -631
  162. package/dist/core/sections/hasItems.d.ts.map +1 -1
  163. package/dist/core/sections/hasItems.js +144 -144
  164. package/dist/core/sections/index.d.ts +4 -4
  165. package/dist/core/sections/index.d.ts.map +1 -1
  166. package/dist/core/sections/index.js +4 -4
  167. package/dist/core/sections/section.d.ts +225 -225
  168. package/dist/core/sections/section.d.ts.map +1 -1
  169. package/dist/core/sections/section.js +341 -341
  170. package/dist/core/sections/simple.d.ts +98 -98
  171. package/dist/core/sections/simple.d.ts.map +1 -1
  172. package/dist/core/sections/simple.js +95 -95
  173. package/dist/core/security/dom.d.ts +10 -10
  174. package/dist/core/security/dom.js +92 -92
  175. package/dist/core/submit/ItemEditSubmit.d.ts +75 -75
  176. package/dist/core/submit/ItemEditSubmit.js +186 -186
  177. package/dist/core/submit/NewItemSubmit.d.ts +13 -13
  178. package/dist/core/submit/NewItemSubmit.js +93 -93
  179. package/dist/core/submit/SimpleSectionSubmit.d.ts +12 -12
  180. package/dist/core/submit/SimpleSectionSubmit.js +93 -93
  181. package/dist/core/submit/index.d.ts +4 -4
  182. package/dist/core/submit/index.js +4 -4
  183. package/dist/core/submit/submit.d.ts +115 -115
  184. package/dist/core/submit/submit.js +479 -479
  185. package/dist/core/types/index.d.ts +279 -279
  186. package/dist/core/types/index.d.ts.map +1 -1
  187. package/dist/core/types/index.js +1 -1
  188. package/dist/db/client.d.ts +8 -8
  189. package/dist/db/client.d.ts.map +1 -1
  190. package/dist/db/client.js +19 -19
  191. package/dist/db/config.d.ts +5 -5
  192. package/dist/db/config.js +22 -22
  193. package/dist/db/drizzle.config.d.ts +5 -5
  194. package/dist/db/drizzle.config.js +18 -18
  195. package/dist/db/index.d.ts +2 -2
  196. package/dist/db/index.js +3 -3
  197. package/dist/db/schema.d.ts +638 -638
  198. package/dist/db/schema.js +73 -73
  199. package/dist/index.d.ts +7 -7
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +7 -7
  202. package/dist/translations/index.d.ts +2 -2
  203. package/dist/translations/index.js +15 -15
  204. package/dist/utils/CpanelApi.d.ts +24 -24
  205. package/dist/utils/CpanelApi.js +64 -64
  206. package/dist/utils/constants.d.ts +13 -13
  207. package/dist/utils/constants.js +61 -61
  208. package/dist/utils/index.d.ts +4 -4
  209. package/dist/utils/index.d.ts.map +1 -1
  210. package/dist/utils/index.js +4 -4
  211. package/dist/utils/utils.d.ts +59 -59
  212. package/dist/utils/utils.js +132 -132
  213. package/dist/validators/checkbox.d.ts +3 -3
  214. package/dist/validators/checkbox.d.ts.map +1 -1
  215. package/dist/validators/checkbox.js +12 -12
  216. package/dist/validators/color.d.ts +3 -3
  217. package/dist/validators/color.d.ts.map +1 -1
  218. package/dist/validators/color.js +7 -7
  219. package/dist/validators/date.d.ts +3 -3
  220. package/dist/validators/date.d.ts.map +1 -1
  221. package/dist/validators/date.js +5 -5
  222. package/dist/validators/document.d.ts +3 -3
  223. package/dist/validators/document.d.ts.map +1 -1
  224. package/dist/validators/document.js +57 -57
  225. package/dist/validators/index.d.ts +14 -14
  226. package/dist/validators/index.d.ts.map +1 -1
  227. package/dist/validators/index.js +14 -14
  228. package/dist/validators/map.d.ts +3 -3
  229. package/dist/validators/map.d.ts.map +1 -1
  230. package/dist/validators/map.js +5 -5
  231. package/dist/validators/number.d.ts +3 -3
  232. package/dist/validators/number.d.ts.map +1 -1
  233. package/dist/validators/number.js +20 -20
  234. package/dist/validators/password.d.ts +3 -3
  235. package/dist/validators/password.d.ts.map +1 -1
  236. package/dist/validators/password.js +11 -11
  237. package/dist/validators/photo.d.ts +3 -3
  238. package/dist/validators/photo.d.ts.map +1 -1
  239. package/dist/validators/photo.js +100 -100
  240. package/dist/validators/richText.d.ts +3 -3
  241. package/dist/validators/richText.d.ts.map +1 -1
  242. package/dist/validators/richText.js +8 -8
  243. package/dist/validators/select-multiple.d.ts +9 -9
  244. package/dist/validators/select-multiple.d.ts.map +1 -1
  245. package/dist/validators/select-multiple.js +20 -20
  246. package/dist/validators/select.d.ts +3 -3
  247. package/dist/validators/select.d.ts.map +1 -1
  248. package/dist/validators/select.js +5 -5
  249. package/dist/validators/text.d.ts +3 -3
  250. package/dist/validators/text.d.ts.map +1 -1
  251. package/dist/validators/text.js +7 -7
  252. package/dist/validators/textarea.d.ts +3 -3
  253. package/dist/validators/textarea.d.ts.map +1 -1
  254. package/dist/validators/textarea.js +7 -7
  255. package/dist/validators/video.d.ts +3 -3
  256. package/dist/validators/video.d.ts.map +1 -1
  257. package/dist/validators/video.js +57 -57
  258. package/package.json +4 -5
@@ -1,347 +1,347 @@
1
- /**
2
- * @module react
3
- */
4
- 'use client';
5
- import * as React from 'react';
6
- import { fetchData, now, useOnline } from "./lib/client.js";
7
- import { useRouter } from 'next/navigation';
8
- import useAxiosPrivate from "./hooks/useAxiosPrivate.js";
9
- import useRefreshToken from "./hooks/useRefreshToken.js";
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.js";
1
+ /**
2
+ * @module react
3
+ */
4
+ 'use client';
5
+ import * as React from 'react';
6
+ import { fetchData, now, useOnline } from './lib/client.js';
7
+ import { useRouter } from 'next/navigation';
8
+ import useAxiosPrivate from './hooks/useAxiosPrivate.js';
9
+ import useRefreshToken from './hooks/useRefreshToken.js';
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';