nextjs-cms 0.0.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -0
  3. package/dist/api/axios/axiosInstance.d.ts +2 -0
  4. package/dist/api/axios/axiosInstance.d.ts.map +1 -0
  5. package/dist/api/axios/axiosInstance.js +8 -0
  6. package/dist/api/index.d.ts +856 -0
  7. package/dist/api/index.d.ts.map +1 -0
  8. package/dist/api/index.js +12 -0
  9. package/dist/api/lib/serverActions.d.ts +240 -0
  10. package/dist/api/lib/serverActions.d.ts.map +1 -0
  11. package/dist/api/lib/serverActions.js +834 -0
  12. package/dist/api/root.d.ts +829 -0
  13. package/dist/api/root.d.ts.map +1 -0
  14. package/dist/api/root.js +30 -0
  15. package/dist/api/routers/accountSettings.d.ts +61 -0
  16. package/dist/api/routers/accountSettings.d.ts.map +1 -0
  17. package/dist/api/routers/accountSettings.js +108 -0
  18. package/dist/api/routers/admins.d.ts +106 -0
  19. package/dist/api/routers/admins.d.ts.map +1 -0
  20. package/dist/api/routers/admins.js +219 -0
  21. package/dist/api/routers/auth.d.ts +48 -0
  22. package/dist/api/routers/auth.d.ts.map +1 -0
  23. package/dist/api/routers/auth.js +25 -0
  24. package/dist/api/routers/categorySection.d.ts +104 -0
  25. package/dist/api/routers/categorySection.d.ts.map +1 -0
  26. package/dist/api/routers/categorySection.js +38 -0
  27. package/dist/api/routers/cmsSettings.d.ts +49 -0
  28. package/dist/api/routers/cmsSettings.d.ts.map +1 -0
  29. package/dist/api/routers/cmsSettings.js +51 -0
  30. package/dist/api/routers/cpanel.d.ts +84 -0
  31. package/dist/api/routers/cpanel.d.ts.map +1 -0
  32. package/dist/api/routers/cpanel.js +216 -0
  33. package/dist/api/routers/files.d.ts +48 -0
  34. package/dist/api/routers/files.d.ts.map +1 -0
  35. package/dist/api/routers/files.js +23 -0
  36. package/dist/api/routers/gallery.d.ts +36 -0
  37. package/dist/api/routers/gallery.d.ts.map +1 -0
  38. package/dist/api/routers/gallery.js +62 -0
  39. package/dist/api/routers/googleAnalytics.d.ts +31 -0
  40. package/dist/api/routers/googleAnalytics.d.ts.map +1 -0
  41. package/dist/api/routers/googleAnalytics.js +7 -0
  42. package/dist/api/routers/hasItemsSection.d.ts +140 -0
  43. package/dist/api/routers/hasItemsSection.d.ts.map +1 -0
  44. package/dist/api/routers/hasItemsSection.js +34 -0
  45. package/dist/api/routers/navigation.d.ts +52 -0
  46. package/dist/api/routers/navigation.d.ts.map +1 -0
  47. package/dist/api/routers/navigation.js +11 -0
  48. package/dist/api/routers/simpleSection.d.ts +58 -0
  49. package/dist/api/routers/simpleSection.d.ts.map +1 -0
  50. package/dist/api/routers/simpleSection.js +12 -0
  51. package/dist/api/trpc.d.ts +107 -0
  52. package/dist/api/trpc.d.ts.map +1 -0
  53. package/dist/api/trpc.js +72 -0
  54. package/dist/auth/axios/axiosInstance.d.ts +2 -0
  55. package/dist/auth/axios/axiosInstance.d.ts.map +1 -0
  56. package/dist/auth/axios/axiosInstance.js +8 -0
  57. package/dist/auth/csrf.d.ts +30 -0
  58. package/dist/auth/csrf.d.ts.map +1 -0
  59. package/dist/auth/csrf.js +76 -0
  60. package/dist/auth/hooks/index.d.ts +4 -0
  61. package/dist/auth/hooks/index.d.ts.map +1 -0
  62. package/dist/auth/hooks/index.js +3 -0
  63. package/dist/auth/hooks/useAxiosPrivate.d.ts +5 -0
  64. package/dist/auth/hooks/useAxiosPrivate.d.ts.map +1 -0
  65. package/dist/auth/hooks/useAxiosPrivate.js +74 -0
  66. package/dist/auth/hooks/useRefreshToken.d.ts +7 -0
  67. package/dist/auth/hooks/useRefreshToken.d.ts.map +1 -0
  68. package/dist/auth/hooks/useRefreshToken.js +79 -0
  69. package/dist/auth/index.d.ts +23 -0
  70. package/dist/auth/index.d.ts.map +1 -0
  71. package/dist/auth/index.js +44 -0
  72. package/dist/auth/jwt.d.ts +6 -0
  73. package/dist/auth/jwt.d.ts.map +1 -0
  74. package/dist/auth/jwt.js +25 -0
  75. package/dist/auth/lib/actions.d.ts +33 -0
  76. package/dist/auth/lib/actions.d.ts.map +1 -0
  77. package/dist/auth/lib/actions.js +209 -0
  78. package/dist/auth/lib/client.d.ts +4 -0
  79. package/dist/auth/lib/client.d.ts.map +1 -0
  80. package/dist/auth/lib/client.js +46 -0
  81. package/dist/auth/lib/index.d.ts +3 -0
  82. package/dist/auth/lib/index.d.ts.map +1 -0
  83. package/dist/auth/lib/index.js +2 -0
  84. package/dist/auth/react.d.ts +106 -0
  85. package/dist/auth/react.d.ts.map +1 -0
  86. package/dist/auth/react.js +347 -0
  87. package/dist/auth/trpc.d.ts +6 -0
  88. package/dist/auth/trpc.d.ts.map +1 -0
  89. package/dist/auth/trpc.js +81 -0
  90. package/dist/core/config/config-loader.d.ts +92 -0
  91. package/dist/core/config/config-loader.d.ts.map +1 -0
  92. package/dist/core/config/config-loader.js +230 -0
  93. package/dist/core/config/index.d.ts +3 -0
  94. package/dist/core/config/index.d.ts.map +1 -0
  95. package/dist/core/config/index.js +1 -0
  96. package/dist/core/config/loader.d.ts +2 -0
  97. package/dist/core/config/loader.d.ts.map +1 -0
  98. package/dist/core/config/loader.js +42 -0
  99. package/dist/core/db/index.d.ts +2 -0
  100. package/dist/core/db/index.d.ts.map +1 -0
  101. package/dist/core/db/index.js +1 -0
  102. package/dist/core/db/table-checker/DbTable.d.ts +6 -0
  103. package/dist/core/db/table-checker/DbTable.d.ts.map +1 -0
  104. package/dist/core/db/table-checker/DbTable.js +5 -0
  105. package/dist/core/db/table-checker/MysqlTable.d.ts +34 -0
  106. package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -0
  107. package/dist/core/db/table-checker/MysqlTable.js +102 -0
  108. package/dist/core/db/table-checker/index.d.ts +2 -0
  109. package/dist/core/db/table-checker/index.d.ts.map +1 -0
  110. package/dist/core/db/table-checker/index.js +1 -0
  111. package/dist/core/factories/FieldFactory.d.ts +124 -0
  112. package/dist/core/factories/FieldFactory.d.ts.map +1 -0
  113. package/dist/core/factories/FieldFactory.js +411 -0
  114. package/dist/core/factories/SectionFactory.d.ts +110 -0
  115. package/dist/core/factories/SectionFactory.d.ts.map +1 -0
  116. package/dist/core/factories/SectionFactory.js +415 -0
  117. package/dist/core/factories/index.d.ts +3 -0
  118. package/dist/core/factories/index.d.ts.map +1 -0
  119. package/dist/core/factories/index.js +2 -0
  120. package/dist/core/fields/checkbox.d.ts +63 -0
  121. package/dist/core/fields/checkbox.d.ts.map +1 -0
  122. package/dist/core/fields/checkbox.js +62 -0
  123. package/dist/core/fields/color.d.ts +84 -0
  124. package/dist/core/fields/color.d.ts.map +1 -0
  125. package/dist/core/fields/color.js +91 -0
  126. package/dist/core/fields/date.d.ts +100 -0
  127. package/dist/core/fields/date.d.ts.map +1 -0
  128. package/dist/core/fields/date.js +108 -0
  129. package/dist/core/fields/document.d.ts +180 -0
  130. package/dist/core/fields/document.d.ts.map +1 -0
  131. package/dist/core/fields/document.js +277 -0
  132. package/dist/core/fields/field-group.d.ts +18 -0
  133. package/dist/core/fields/field-group.d.ts.map +1 -0
  134. package/dist/core/fields/field-group.js +6 -0
  135. package/dist/core/fields/field.d.ts +126 -0
  136. package/dist/core/fields/field.d.ts.map +1 -0
  137. package/dist/core/fields/field.js +148 -0
  138. package/dist/core/fields/fileField.d.ts +15 -0
  139. package/dist/core/fields/fileField.d.ts.map +1 -0
  140. package/dist/core/fields/fileField.js +5 -0
  141. package/dist/core/fields/index.d.ts +65 -0
  142. package/dist/core/fields/index.d.ts.map +1 -0
  143. package/dist/core/fields/index.js +18 -0
  144. package/dist/core/fields/map.d.ts +167 -0
  145. package/dist/core/fields/map.d.ts.map +1 -0
  146. package/dist/core/fields/map.js +152 -0
  147. package/dist/core/fields/number.d.ts +186 -0
  148. package/dist/core/fields/number.d.ts.map +1 -0
  149. package/dist/core/fields/number.js +241 -0
  150. package/dist/core/fields/password.d.ts +109 -0
  151. package/dist/core/fields/password.d.ts.map +1 -0
  152. package/dist/core/fields/password.js +133 -0
  153. package/dist/core/fields/photo.d.ts +289 -0
  154. package/dist/core/fields/photo.d.ts.map +1 -0
  155. package/dist/core/fields/photo.js +410 -0
  156. package/dist/core/fields/richText.d.ts +295 -0
  157. package/dist/core/fields/richText.d.ts.map +1 -0
  158. package/dist/core/fields/richText.js +338 -0
  159. package/dist/core/fields/select.d.ts +366 -0
  160. package/dist/core/fields/select.d.ts.map +1 -0
  161. package/dist/core/fields/select.js +499 -0
  162. package/dist/core/fields/selectMultiple.d.ts +236 -0
  163. package/dist/core/fields/selectMultiple.d.ts.map +1 -0
  164. package/dist/core/fields/selectMultiple.js +417 -0
  165. package/dist/core/fields/tags.d.ts +131 -0
  166. package/dist/core/fields/tags.d.ts.map +1 -0
  167. package/dist/core/fields/tags.js +105 -0
  168. package/dist/core/fields/text.d.ts +136 -0
  169. package/dist/core/fields/text.d.ts.map +1 -0
  170. package/dist/core/fields/text.js +157 -0
  171. package/dist/core/fields/textArea.d.ts +107 -0
  172. package/dist/core/fields/textArea.d.ts.map +1 -0
  173. package/dist/core/fields/textArea.js +126 -0
  174. package/dist/core/fields/video.d.ts +148 -0
  175. package/dist/core/fields/video.d.ts.map +1 -0
  176. package/dist/core/fields/video.js +248 -0
  177. package/dist/core/helpers/entity.d.ts +8 -0
  178. package/dist/core/helpers/entity.d.ts.map +1 -0
  179. package/dist/core/helpers/entity.js +27 -0
  180. package/dist/core/helpers/index.d.ts +5 -0
  181. package/dist/core/helpers/index.d.ts.map +1 -0
  182. package/dist/core/helpers/index.js +3 -0
  183. package/dist/core/index.d.ts +8 -0
  184. package/dist/core/index.d.ts.map +1 -0
  185. package/dist/core/index.js +7 -0
  186. package/dist/core/sections/category.d.ts +283 -0
  187. package/dist/core/sections/category.d.ts.map +1 -0
  188. package/dist/core/sections/category.js +147 -0
  189. package/dist/core/sections/hasItems.d.ts +632 -0
  190. package/dist/core/sections/hasItems.d.ts.map +1 -0
  191. package/dist/core/sections/hasItems.js +144 -0
  192. package/dist/core/sections/index.d.ts +5 -0
  193. package/dist/core/sections/index.d.ts.map +1 -0
  194. package/dist/core/sections/index.js +4 -0
  195. package/dist/core/sections/section.d.ts +226 -0
  196. package/dist/core/sections/section.d.ts.map +1 -0
  197. package/dist/core/sections/section.js +341 -0
  198. package/dist/core/sections/simple.d.ts +99 -0
  199. package/dist/core/sections/simple.d.ts.map +1 -0
  200. package/dist/core/sections/simple.js +95 -0
  201. package/dist/core/security/dom.d.ts +11 -0
  202. package/dist/core/security/dom.d.ts.map +1 -0
  203. package/dist/core/security/dom.js +92 -0
  204. package/dist/core/submit/ItemEditSubmit.d.ts +76 -0
  205. package/dist/core/submit/ItemEditSubmit.d.ts.map +1 -0
  206. package/dist/core/submit/ItemEditSubmit.js +186 -0
  207. package/dist/core/submit/NewItemSubmit.d.ts +14 -0
  208. package/dist/core/submit/NewItemSubmit.d.ts.map +1 -0
  209. package/dist/core/submit/NewItemSubmit.js +93 -0
  210. package/dist/core/submit/SimpleSectionSubmit.d.ts +13 -0
  211. package/dist/core/submit/SimpleSectionSubmit.d.ts.map +1 -0
  212. package/dist/core/submit/SimpleSectionSubmit.js +93 -0
  213. package/dist/core/submit/index.d.ts +5 -0
  214. package/dist/core/submit/index.d.ts.map +1 -0
  215. package/dist/core/submit/index.js +4 -0
  216. package/dist/core/submit/submit.d.ts +116 -0
  217. package/dist/core/submit/submit.d.ts.map +1 -0
  218. package/dist/core/submit/submit.js +479 -0
  219. package/dist/core/types/index.d.ts +280 -0
  220. package/dist/core/types/index.d.ts.map +1 -0
  221. package/dist/core/types/index.js +1 -0
  222. package/dist/db/client.d.ts +9 -0
  223. package/dist/db/client.d.ts.map +1 -0
  224. package/dist/db/client.js +19 -0
  225. package/dist/db/config.d.ts +6 -0
  226. package/dist/db/config.d.ts.map +1 -0
  227. package/dist/db/config.js +22 -0
  228. package/dist/db/drizzle.config.d.ts +6 -0
  229. package/dist/db/drizzle.config.d.ts.map +1 -0
  230. package/dist/db/drizzle.config.js +18 -0
  231. package/dist/db/index.d.ts +3 -0
  232. package/dist/db/index.d.ts.map +1 -0
  233. package/dist/db/index.js +3 -0
  234. package/dist/db/schema.d.ts +639 -0
  235. package/dist/db/schema.d.ts.map +1 -0
  236. package/dist/db/schema.js +73 -0
  237. package/dist/index.d.ts +7 -1
  238. package/dist/index.d.ts.map +1 -1
  239. package/dist/index.js +7 -1
  240. package/dist/translations/dictionaries/ar.json +279 -0
  241. package/dist/translations/dictionaries/en.json +279 -0
  242. package/dist/translations/index.d.ts +3 -0
  243. package/dist/translations/index.d.ts.map +1 -0
  244. package/dist/translations/index.js +15 -0
  245. package/dist/utils/CpanelApi.d.ts +25 -0
  246. package/dist/utils/CpanelApi.d.ts.map +1 -0
  247. package/dist/utils/CpanelApi.js +64 -0
  248. package/dist/utils/constants.d.ts +14 -0
  249. package/dist/utils/constants.d.ts.map +1 -0
  250. package/dist/utils/constants.js +61 -0
  251. package/dist/utils/index.d.ts +5 -0
  252. package/dist/utils/index.d.ts.map +1 -0
  253. package/dist/utils/index.js +4 -0
  254. package/dist/utils/utils.d.ts +60 -0
  255. package/dist/utils/utils.d.ts.map +1 -0
  256. package/dist/utils/utils.js +132 -0
  257. package/dist/validators/checkbox.d.ts +4 -0
  258. package/dist/validators/checkbox.d.ts.map +1 -0
  259. package/dist/validators/checkbox.js +12 -0
  260. package/dist/validators/color.d.ts +4 -0
  261. package/dist/validators/color.d.ts.map +1 -0
  262. package/dist/validators/color.js +7 -0
  263. package/dist/validators/date.d.ts +4 -0
  264. package/dist/validators/date.d.ts.map +1 -0
  265. package/dist/validators/date.js +5 -0
  266. package/dist/validators/document.d.ts +4 -0
  267. package/dist/validators/document.d.ts.map +1 -0
  268. package/dist/validators/document.js +57 -0
  269. package/dist/validators/index.d.ts +15 -0
  270. package/dist/validators/index.d.ts.map +1 -0
  271. package/dist/validators/index.js +14 -0
  272. package/dist/validators/map.d.ts +4 -0
  273. package/dist/validators/map.d.ts.map +1 -0
  274. package/dist/validators/map.js +5 -0
  275. package/dist/validators/number.d.ts +4 -0
  276. package/dist/validators/number.d.ts.map +1 -0
  277. package/dist/validators/number.js +20 -0
  278. package/dist/validators/password.d.ts +4 -0
  279. package/dist/validators/password.d.ts.map +1 -0
  280. package/dist/validators/password.js +11 -0
  281. package/dist/validators/photo.d.ts +4 -0
  282. package/dist/validators/photo.d.ts.map +1 -0
  283. package/dist/validators/photo.js +100 -0
  284. package/dist/validators/richText.d.ts +4 -0
  285. package/dist/validators/richText.d.ts.map +1 -0
  286. package/dist/validators/richText.js +8 -0
  287. package/dist/validators/select-multiple.d.ts +10 -0
  288. package/dist/validators/select-multiple.d.ts.map +1 -0
  289. package/dist/validators/select-multiple.js +20 -0
  290. package/dist/validators/select.d.ts +4 -0
  291. package/dist/validators/select.d.ts.map +1 -0
  292. package/dist/validators/select.js +5 -0
  293. package/dist/validators/text.d.ts +4 -0
  294. package/dist/validators/text.d.ts.map +1 -0
  295. package/dist/validators/text.js +7 -0
  296. package/dist/validators/textarea.d.ts +4 -0
  297. package/dist/validators/textarea.d.ts.map +1 -0
  298. package/dist/validators/textarea.js +7 -0
  299. package/dist/validators/video.d.ts +4 -0
  300. package/dist/validators/video.d.ts.map +1 -0
  301. package/dist/validators/video.js +57 -0
  302. package/package.json +150 -6
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+ import React from 'react';
3
+ import { getCsrfToken } from '../react';
4
+ export async function fetchData(path, req = {}) {
5
+ const url = `/api/auth/${path}`;
6
+ try {
7
+ const options = {
8
+ headers: {
9
+ // If there is a body, add the x-csrf-token header
10
+ ...(req?.body ? { 'x-csrf-token': await getCsrfToken() } : {}),
11
+ 'Content-Type': 'application/json',
12
+ ...(req?.headers?.cookie ? { cookie: req.headers.cookie } : {}),
13
+ },
14
+ };
15
+ if (req?.body) {
16
+ options.body = JSON.stringify(req.body);
17
+ options.method = 'POST';
18
+ }
19
+ const res = await fetch(url, options);
20
+ const data = await res.json();
21
+ if (!res.ok)
22
+ throw data;
23
+ return data;
24
+ }
25
+ catch (error) {
26
+ console.error(error.message);
27
+ return null;
28
+ }
29
+ }
30
+ export function now() {
31
+ return Math.floor(Date.now() / 1000);
32
+ }
33
+ export function useOnline() {
34
+ const [isOnline, setIsOnline] = React.useState(typeof navigator !== 'undefined' ? navigator.onLine : false);
35
+ const setOnline = () => setIsOnline(true);
36
+ const setOffline = () => setIsOnline(false);
37
+ React.useEffect(() => {
38
+ window.addEventListener('online', setOnline);
39
+ window.addEventListener('offline', setOffline);
40
+ return () => {
41
+ window.removeEventListener('online', setOnline);
42
+ window.removeEventListener('offline', setOffline);
43
+ };
44
+ }, []);
45
+ return isOnline;
46
+ }
@@ -0,0 +1,3 @@
1
+ export { deleteSession, login, authRefresh } from './actions';
2
+ export { createCSRFToken, validateCSRFToken } from '../csrf';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { deleteSession, login, authRefresh } from './actions';
2
+ export { createCSRFToken, validateCSRFToken } from '../csrf';
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @module react
3
+ */
4
+ import * as React from 'react';
5
+ import type { Session } from './index';
6
+ import useAxiosPrivate from './hooks/useAxiosPrivate';
7
+ import useRefreshToken from './hooks/useRefreshToken';
8
+ export type UpdateSession = (data?: any) => Promise<Session | null>;
9
+ export interface SessionProviderProps {
10
+ children: React.ReactNode;
11
+ session?: Session | null;
12
+ /**
13
+ * A time interval (in seconds) after which the session will be re-fetched.
14
+ * If set to `0` (default), the session is not polled.
15
+ */
16
+ refetchInterval?: number;
17
+ /**
18
+ * `SessionProvider` automatically re-fetches the session when the user switches between windows.
19
+ * This option activates this behaviour if set to `true` (default).
20
+ */
21
+ refetchOnWindowFocus?: boolean;
22
+ /**
23
+ * Set to `false` to stop polling when the device has no internet access offline (determined by `navigator.onLine`)
24
+ *
25
+ * [`navigator.onLine` documentation](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine)
26
+ */
27
+ refetchWhenOffline?: false;
28
+ }
29
+ export interface UseSessionOptions<R extends boolean> {
30
+ required: R;
31
+ /** Defaults to `signIn` */
32
+ onUnauthenticated?: () => void;
33
+ }
34
+ export interface GetSessionParams {
35
+ event?: 'storage' | 'timer' | 'hidden' | string;
36
+ triggerEvent?: boolean;
37
+ broadcast?: boolean;
38
+ }
39
+ export interface AuthClientConfig {
40
+ _session?: Session | null | undefined;
41
+ /** Used for timestamp since last synced (in seconds) */
42
+ _lastSync: number;
43
+ /**
44
+ * Stores the `SessionProvider`'s session update method to be able to
45
+ * trigger session updates from places like `signIn` or `signOut`
46
+ */
47
+ _getSession: (...args: any[]) => any;
48
+ }
49
+ export declare const __AUTH: AuthClientConfig;
50
+ export declare function logout(options?: {
51
+ deleteCookies?: boolean;
52
+ }): Promise<void>;
53
+ export declare function login({ username, password }: {
54
+ username: string;
55
+ password: string;
56
+ }): Promise<void>;
57
+ export declare function refreshSession(): Promise<void>;
58
+ /**
59
+ * Returns the current CSRF token.
60
+ * required to make requests that changes state.
61
+ *
62
+ * [CSRF Prevention: Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)
63
+ */
64
+ export declare function getCsrfToken(): Promise<string>;
65
+ export declare function getSession(params?: GetSessionParams): Promise<Session | null>;
66
+ export type SessionContextValue<R extends boolean = false> = R extends true ? {
67
+ update: UpdateSession;
68
+ data: Session;
69
+ status: 'authenticated';
70
+ } | {
71
+ update: UpdateSession;
72
+ data: null;
73
+ status: 'loading';
74
+ } : {
75
+ update: UpdateSession;
76
+ data: Session;
77
+ status: 'authenticated';
78
+ } | {
79
+ update: UpdateSession;
80
+ data: null;
81
+ status: 'unauthenticated' | 'loading';
82
+ };
83
+ export declare const SessionContext: React.Context<{
84
+ update: UpdateSession;
85
+ data: Session;
86
+ status: "authenticated";
87
+ } | {
88
+ update: UpdateSession;
89
+ data: null;
90
+ status: "unauthenticated" | "loading";
91
+ } | undefined>;
92
+ export declare function useSession<R extends boolean>(options?: UseSessionOptions<R>): SessionContextValue<R>;
93
+ /**
94
+ * [React Context](https://react.dev/learn/passing-data-deeply-with-context) provider to wrap the app (`pages/`) to make session data available anywhere.
95
+ *
96
+ * When used, the session state is automatically synchronized across all open tabs/windows and they are all updated whenever they gain or lose focus
97
+ * or the state changes (e.g. a user signs in or out) when {@link SessionProviderProps.refetchOnWindowFocus} is `true`.
98
+ *
99
+ * :::info
100
+ * `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.
101
+ * :::
102
+ */
103
+ export declare function SessionProvider(props: SessionProviderProps): React.JSX.Element;
104
+ export { useAxiosPrivate, useRefreshToken };
105
+ export { refreshTokenLink } from './trpc';
106
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/auth/react.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,eAAe,MAAM,yBAAyB,CAAA;AACrD,OAAO,eAAe,MAAM,yBAAyB,CAAA;AAGrD,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;AACnE,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAC7B;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,OAAO;IAChD,QAAQ,EAAE,CAAC,CAAA;IACX,2BAA2B;IAC3B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;IACrC,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,WAAW,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;CACvC;AAED,eAAO,MAAM,MAAM,EAAE,gBAIpB,CAAA;AAED,wBAAsB,MAAM,CAAC,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,iBA2BjE;AAED,wBAAsB,KAAK,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,iBAyBzF;AAED,wBAAsB,cAAc,kBAWnC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,oBAGjC;AAwBD,wBAAsB,UAAU,CAAC,MAAM,CAAC,EAAE,gBAAgB,2BAWzD;AAED,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,OAAO,GAAG,KAAK,IAAI,CAAC,SAAS,IAAI,GAE/D;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GACjE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAExD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GACjE;IACI,MAAM,EAAE,aAAa,CAAA;IACrB,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAA;CACxC,CAAA;AAEb,eAAO,MAAM,cAAc;YAPL,aAAa;UAAQ,OAAO;YAAU,eAAe;;YAEnD,aAAa;UACf,IAAI;YACF,iBAAiB,GAAG,SAAS;cAG0C,CAAA;AAE/F,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CA6BpG;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,qBAiN1D;AAED,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAA"}
@@ -0,0 +1,347 @@
1
+ /**
2
+ * @module react
3
+ */
4
+ 'use client';
5
+ import * as React from 'react';
6
+ import { fetchData, now, useOnline } from './lib/client';
7
+ import { useRouter } from 'next/navigation';
8
+ import useAxiosPrivate from './hooks/useAxiosPrivate';
9
+ import useRefreshToken from './hooks/useRefreshToken';
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';
@@ -0,0 +1,6 @@
1
+ import type { TRPCLink } from '@trpc/client';
2
+ /**
3
+ * tRPC link that refreshes the token if it's expired
4
+ */
5
+ export declare const refreshTokenLink: () => TRPCLink</*AppRouter*/ any>;
6
+ //# sourceMappingURL=trpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../../src/auth/trpc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAM5C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAO,QAAQ,CAAC,aAAa,CAAA,GAAG,CA4E5D,CAAA"}
@@ -0,0 +1,81 @@
1
+ import { observable } from '@trpc/server/observable';
2
+ // import type { AppRouter } from '../api'
3
+ import { logout, refreshSession } from './react';
4
+ /**
5
+ * tRPC link that refreshes the token if it's expired
6
+ */
7
+ export const refreshTokenLink = () => {
8
+ /**
9
+ * Add a lock state to prevent multiple refreshes at the same time
10
+ */
11
+ let isRefreshing = false;
12
+ let refreshPromise = null;
13
+ return () => {
14
+ return ({ next, op }) => {
15
+ return observable((observer) => {
16
+ let next$ = null;
17
+ let shouldRetry = true; // Flag to control the retry
18
+ function attempt() {
19
+ next$?.unsubscribe();
20
+ next$ = next(op).subscribe({
21
+ async error(err) {
22
+ if (err.data?.code === 'UNAUTHORIZED' && shouldRetry) {
23
+ if (!isRefreshing) {
24
+ isRefreshing = true;
25
+ refreshPromise = (async () => {
26
+ try {
27
+ const response = await fetch('/api/auth/refresh');
28
+ if (response.status !== 200) {
29
+ await logout({
30
+ /**
31
+ * No need to delete the cookies, because they are both invalid.
32
+ */
33
+ deleteCookies: false,
34
+ });
35
+ return;
36
+ }
37
+ await refreshSession();
38
+ }
39
+ catch (e) {
40
+ await logout({
41
+ /**
42
+ * No need to delete the cookies, because they are both invalid.
43
+ */
44
+ deleteCookies: false,
45
+ });
46
+ throw e;
47
+ }
48
+ finally {
49
+ isRefreshing = false;
50
+ refreshPromise = null;
51
+ }
52
+ })();
53
+ }
54
+ try {
55
+ await refreshPromise;
56
+ shouldRetry = false;
57
+ attempt();
58
+ return;
59
+ }
60
+ catch (e) {
61
+ // Don't throw under-the-hood refresh flow's errors
62
+ }
63
+ }
64
+ observer.error(err);
65
+ },
66
+ next(value) {
67
+ observer.next(value);
68
+ },
69
+ complete() {
70
+ observer.complete();
71
+ },
72
+ });
73
+ }
74
+ attempt();
75
+ return () => {
76
+ next$?.unsubscribe();
77
+ };
78
+ });
79
+ };
80
+ };
81
+ };