@civic/auth 0.1.5-beta.1 → 0.1.5-beta.2

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 (37) hide show
  1. package/dist/cjs/nextjs/hooks/usePrevious.d.ts +2 -0
  2. package/dist/cjs/nextjs/hooks/usePrevious.d.ts.map +1 -0
  3. package/dist/cjs/nextjs/hooks/usePrevious.js +12 -0
  4. package/dist/cjs/nextjs/hooks/usePrevious.js.map +1 -0
  5. package/dist/cjs/nextjs/hooks/useUserCookie.d.ts +2 -0
  6. package/dist/cjs/nextjs/hooks/useUserCookie.d.ts.map +1 -1
  7. package/dist/cjs/nextjs/hooks/useUserCookie.js +43 -22
  8. package/dist/cjs/nextjs/hooks/useUserCookie.js.map +1 -1
  9. package/dist/cjs/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  10. package/dist/cjs/nextjs/providers/NextAuthProvider.js +22 -7
  11. package/dist/cjs/nextjs/providers/NextAuthProvider.js.map +1 -1
  12. package/dist/cjs/reactjs/providers/AuthProvider.d.ts.map +1 -1
  13. package/dist/cjs/reactjs/providers/AuthProvider.js +5 -1
  14. package/dist/cjs/reactjs/providers/AuthProvider.js.map +1 -1
  15. package/dist/cjs/shared/version.d.ts +1 -1
  16. package/dist/cjs/shared/version.js +1 -1
  17. package/dist/cjs/shared/version.js.map +1 -1
  18. package/dist/esm/nextjs/hooks/usePrevious.d.ts +2 -0
  19. package/dist/esm/nextjs/hooks/usePrevious.d.ts.map +1 -0
  20. package/dist/esm/nextjs/hooks/usePrevious.js +9 -0
  21. package/dist/esm/nextjs/hooks/usePrevious.js.map +1 -0
  22. package/dist/esm/nextjs/hooks/useUserCookie.d.ts +2 -0
  23. package/dist/esm/nextjs/hooks/useUserCookie.d.ts.map +1 -1
  24. package/dist/esm/nextjs/hooks/useUserCookie.js +43 -22
  25. package/dist/esm/nextjs/hooks/useUserCookie.js.map +1 -1
  26. package/dist/esm/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  27. package/dist/esm/nextjs/providers/NextAuthProvider.js +22 -7
  28. package/dist/esm/nextjs/providers/NextAuthProvider.js.map +1 -1
  29. package/dist/esm/reactjs/providers/AuthProvider.d.ts.map +1 -1
  30. package/dist/esm/reactjs/providers/AuthProvider.js +5 -1
  31. package/dist/esm/reactjs/providers/AuthProvider.js.map +1 -1
  32. package/dist/esm/shared/version.d.ts +1 -1
  33. package/dist/esm/shared/version.js +1 -1
  34. package/dist/esm/shared/version.js.map +1 -1
  35. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  36. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export declare function usePrevious<T>(value: T): T | undefined;
2
+ //# sourceMappingURL=usePrevious.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrevious.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/usePrevious.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,iBAMtC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePrevious = usePrevious;
4
+ const react_1 = require("react");
5
+ function usePrevious(value) {
6
+ const ref = (0, react_1.useRef)();
7
+ (0, react_1.useEffect)(() => {
8
+ ref.current = value;
9
+ }, [value]);
10
+ return ref.current;
11
+ }
12
+ //# sourceMappingURL=usePrevious.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrevious.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/usePrevious.ts"],"names":[],"mappings":";;AAEA,kCAMC;AARD,iCAA0C;AAE1C,SAAgB,WAAW,CAAI,KAAQ;IACrC,MAAM,GAAG,GAAG,IAAA,cAAM,GAAK,CAAC;IACxB,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACZ,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC","sourcesContent":["import { useEffect, useRef } from \"react\";\n\nexport function usePrevious<T>(value: T) {\n const ref = useRef<T>();\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"]}
@@ -2,5 +2,7 @@ import type { EmptyObject, User } from "../../types.js";
2
2
  export declare const useUserCookie: <T extends EmptyObject>() => {
3
3
  user: User<T> | null;
4
4
  idToken: string | undefined;
5
+ fetchUser: (abortController?: AbortController) => Promise<void>;
6
+ isPending: boolean;
5
7
  };
6
8
  //# sourceMappingURL=useUserCookie.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAqBpD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,WAAW;;;CAqDlD,CAAC"}
1
+ {"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAuBpD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,WAAW;;;kCAatB,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC;;CAoE3D,CAAC"}
@@ -6,6 +6,8 @@ const react_1 = require("react");
6
6
  const navigation_js_1 = require("next/navigation.js");
7
7
  const cookies_js_1 = require("../../lib/cookies.js");
8
8
  const types_js_1 = require("../../shared/lib/types.js");
9
+ const usePrevious_js_1 = require("./usePrevious.js");
10
+ const react_2 = require("react");
9
11
  const getUserAndTokenFromCookie = () => (0, cookies_js_1.getWindowCookieValue)([
10
12
  {
11
13
  key: types_js_1.UserStorage.USER,
@@ -21,50 +23,69 @@ const getUserAndTokenFromCookie = () => (0, cookies_js_1.getWindowCookieValue)([
21
23
  const useUserCookie = () => {
22
24
  const [user, setUser] = (0, react_1.useState)(null);
23
25
  const [idToken, setIdToken] = (0, react_1.useState)();
26
+ const [userChanged, setUserChanged] = (0, react_1.useState)(false);
24
27
  const hasRunRef = (0, react_1.useRef)(false);
28
+ const [isPending, startTransition] = (0, react_2.useTransition)();
25
29
  const router = (0, navigation_js_1.useRouter)();
30
+ const prevUser = (0, usePrevious_js_1.usePrevious)(user);
31
+ const prevPending = (0, usePrevious_js_1.usePrevious)(isPending);
26
32
  const fetchUser = (0, react_1.useCallback)(async (abortController) => {
27
- if (abortController.signal.aborted)
33
+ if (abortController?.signal.aborted)
28
34
  return;
29
- if (!hasRunRef.current) {
30
- const response = getUserAndTokenFromCookie() || {};
31
- const userData = response[types_js_1.UserStorage.USER];
32
- const tokenData = response[types_js_1.OAuthTokens.ID_TOKEN];
33
- if (abortController.signal.aborted)
34
- return;
35
- setIdToken(tokenData);
36
- setUser(userData || null);
37
- }
35
+ const response = getUserAndTokenFromCookie() || {};
36
+ const userData = response[types_js_1.UserStorage.USER];
37
+ const tokenData = response[types_js_1.OAuthTokens.ID_TOKEN];
38
+ if (abortController?.signal.aborted)
39
+ return;
40
+ setIdToken(tokenData);
41
+ setUser(userData || null);
38
42
  }, []);
43
+ // call fetch immediately after a refresh
39
44
  (0, react_1.useEffect)(() => {
40
- const abortController = new AbortController();
41
- const intervalId = setInterval(() => {
42
- fetchUser(abortController);
43
- }, 2000);
44
- const handleFocus = () => {
45
+ if (prevPending && !isPending) {
46
+ fetchUser();
47
+ }
48
+ }, [prevPending, isPending, fetchUser]);
49
+ (0, react_1.useEffect)(() => {
50
+ if (prevUser !== user) {
51
+ setUserChanged(true);
52
+ }
53
+ }, [user, prevUser]);
54
+ (0, react_1.useEffect)(() => {
55
+ let abortController = new AbortController();
56
+ const cookieListener = () => {
57
+ abortController = new AbortController();
45
58
  fetchUser(abortController);
46
59
  };
47
- window.addEventListener("focus", handleFocus);
48
- // call fetchUser on load to get initial user if present
60
+ document.addEventListener("visibilitychange", cookieListener);
61
+ window.addEventListener("storage", cookieListener);
62
+ window.addEventListener("focus", cookieListener);
49
63
  fetchUser(abortController);
64
+ const intervalId = setInterval(cookieListener, 2000);
50
65
  return () => {
51
66
  abortController.abort();
67
+ document.removeEventListener("visibilitychange", cookieListener);
68
+ window.removeEventListener("storage", cookieListener);
69
+ window.removeEventListener("focus", cookieListener);
52
70
  clearInterval(intervalId);
53
- window.removeEventListener("focus", handleFocus);
54
71
  };
55
72
  }, [fetchUser]);
56
73
  (0, react_1.useEffect)(() => {
57
- if (user) {
74
+ if (userChanged) {
58
75
  if (!hasRunRef.current) {
59
76
  hasRunRef.current = true;
60
- router.refresh();
77
+ setUserChanged(false);
78
+ startTransition(() => {
79
+ router.refresh();
80
+ });
61
81
  }
62
82
  }
63
83
  else {
64
84
  hasRunRef.current = false;
65
85
  }
66
- }, [user, router]);
67
- return { user, idToken };
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ }, [userChanged]);
88
+ return { user, idToken, fetchUser, isPending };
68
89
  };
69
90
  exports.useUserCookie = useUserCookie;
70
91
  //# sourceMappingURL=useUserCookie.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;AACb,iCAAiE;AACjE,sDAA+C;AAC/C,iDAAwD;AAExD,oDAAiE;AAMjE,MAAM,yBAAyB,GAAG,GAA2B,EAAE,CAC7D,IAAA,iCAAoB,EAAC;IACnB;QACE,GAAG,EAAE,sBAAW,CAAC,IAAI;QACrB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,SAAS,EAAE,IAAI;KAChB;IACD;QACE,GAAG,EAAE,sBAAW,CAAC,QAAQ;QACzB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,SAAS,EAAE,KAAK;KACjB;CACF,CAA2B,CAAC;AAExB,MAAM,aAAa,GAAG,GAA0B,EAAE;IACvD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAA,gBAAQ,EAAiB,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,GAAsB,CAAC;IAC7D,MAAM,SAAS,GAAG,IAAA,cAAM,EAAC,KAAK,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,IAAA,yBAAS,GAAE,CAAC;IAE3B,MAAM,SAAS,GAAG,IAAA,mBAAW,EAAC,KAAK,EAAE,eAAgC,EAAE,EAAE;QACvE,IAAI,eAAe,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO;QAC3C,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,yBAAyB,EAAE,IAAI,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,sBAAW,CAAC,IAAI,CAAY,CAAC;YACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,sBAAW,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,eAAe,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO;YAE3C,UAAU,CAAC,SAAS,CAAC,CAAC;YACtB,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC7B,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,SAAS,CAAC,eAAe,CAAC,CAAC;QAC7B,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAE9C,wDAAwD;QACxD,SAAS,CAAC,eAAe,CAAC,CAAC;QAE3B,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,KAAK,EAAE,CAAC;YACxB,aAAa,CAAC,UAAU,CAAC,CAAC;YAC1B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACnD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACvB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;gBACzB,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC,CAAC;AArDW,QAAA,aAAa,iBAqDxB","sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { getWindowCookieValue } from \"@/lib/cookies.js\";\nimport type { EmptyObject, User } from \"@/types.js\";\nimport { OAuthTokens, UserStorage } from \"@/shared/lib/types.js\";\n\ntype UserAndTokenFromCookie = {\n [UserStorage.USER]: User | undefined;\n [OAuthTokens.ID_TOKEN]: string | undefined;\n};\nconst getUserAndTokenFromCookie = (): UserAndTokenFromCookie =>\n getWindowCookieValue([\n {\n key: UserStorage.USER,\n window: globalThis.window,\n parseJson: true,\n },\n {\n key: OAuthTokens.ID_TOKEN,\n window: globalThis.window,\n parseJson: false,\n },\n ]) as UserAndTokenFromCookie;\n\nexport const useUserCookie = <T extends EmptyObject>() => {\n const [user, setUser] = useState<User<T> | null>(null);\n const [idToken, setIdToken] = useState<string | undefined>();\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n const fetchUser = useCallback(async (abortController: AbortController) => {\n if (abortController.signal.aborted) return;\n if (!hasRunRef.current) {\n const response = getUserAndTokenFromCookie() || {};\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokens.ID_TOKEN];\n if (abortController.signal.aborted) return;\n\n setIdToken(tokenData);\n setUser(userData || null);\n }\n }, []);\n\n useEffect(() => {\n const abortController = new AbortController();\n const intervalId = setInterval(() => {\n fetchUser(abortController);\n }, 2000);\n\n const handleFocus = () => {\n fetchUser(abortController);\n };\n\n window.addEventListener(\"focus\", handleFocus);\n\n // call fetchUser on load to get initial user if present\n fetchUser(abortController);\n\n return () => {\n abortController.abort();\n clearInterval(intervalId);\n window.removeEventListener(\"focus\", handleFocus);\n };\n }, [fetchUser]);\n\n useEffect(() => {\n if (user) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n router.refresh();\n }\n } else {\n hasRunRef.current = false;\n }\n }, [user, router]);\n\n return { user, idToken };\n};\n"]}
1
+ {"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { getWindowCookieValue } from \"@/lib/cookies.js\";\nimport type { EmptyObject, User } from \"@/types.js\";\nimport { OAuthTokens, UserStorage } from \"@/shared/lib/types.js\";\nimport { usePrevious } from \"./usePrevious.js\";\nimport { useTransition } from \"react\";\n\ntype UserAndTokenFromCookie = {\n [UserStorage.USER]: User | undefined;\n [OAuthTokens.ID_TOKEN]: string | undefined;\n};\nconst getUserAndTokenFromCookie = (): UserAndTokenFromCookie =>\n getWindowCookieValue([\n {\n key: UserStorage.USER,\n window: globalThis.window,\n parseJson: true,\n },\n {\n key: OAuthTokens.ID_TOKEN,\n window: globalThis.window,\n parseJson: false,\n },\n ]) as UserAndTokenFromCookie;\n\nexport const useUserCookie = <T extends EmptyObject>() => {\n const [user, setUser] = useState<User<T> | null>(null);\n const [idToken, setIdToken] = useState<string | undefined>();\n const [userChanged, setUserChanged] = useState<boolean>(false);\n const hasRunRef = useRef(false);\n const [isPending, startTransition] = useTransition();\n\n const router = useRouter();\n\n const prevUser = usePrevious(user);\n const prevPending = usePrevious(isPending);\n\n const fetchUser = useCallback(\n async (abortController?: AbortController): Promise<void> => {\n if (abortController?.signal.aborted) return;\n\n const response = getUserAndTokenFromCookie() || {};\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokens.ID_TOKEN];\n\n if (abortController?.signal.aborted) return;\n\n setIdToken(tokenData);\n setUser(userData || null);\n },\n [],\n );\n\n // call fetch immediately after a refresh\n useEffect(() => {\n if (prevPending && !isPending) {\n fetchUser();\n }\n }, [prevPending, isPending, fetchUser]);\n\n useEffect(() => {\n if (prevUser !== user) {\n setUserChanged(true);\n }\n }, [user, prevUser]);\n\n useEffect(() => {\n let abortController = new AbortController();\n const cookieListener = () => {\n abortController = new AbortController();\n fetchUser(abortController);\n };\n\n document.addEventListener(\"visibilitychange\", cookieListener);\n window.addEventListener(\"storage\", cookieListener);\n window.addEventListener(\"focus\", cookieListener);\n\n fetchUser(abortController);\n\n const intervalId = setInterval(cookieListener, 2000);\n\n return () => {\n abortController.abort();\n document.removeEventListener(\"visibilitychange\", cookieListener);\n window.removeEventListener(\"storage\", cookieListener);\n window.removeEventListener(\"focus\", cookieListener);\n clearInterval(intervalId);\n };\n }, [fetchUser]);\n\n useEffect(() => {\n if (userChanged) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n setUserChanged(false);\n startTransition(() => {\n router.refresh();\n });\n }\n } else {\n hasRunRef.current = false;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [userChanged]);\n\n return { user, idToken, fetchUser, isPending };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AACA;;GAEG;AACH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAiB5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAMrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;AAoFF,QAAA,MAAM,qBAAqB,2BAGxB,0BAA0B,sBAwC5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
1
+ {"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AACA;;GAEG;AACH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAiB5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAWrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;AA2GF,QAAA,MAAM,qBAAqB,2BAGxB,0BAA0B,sBAwC5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
@@ -56,17 +56,26 @@ const BlockDisplay_js_1 = require("../../shared/components/BlockDisplay.js");
56
56
  const LoadingIcon_js_1 = require("../../shared/components/LoadingIcon.js");
57
57
  const useIframe_js_1 = require("../../shared/hooks/useIframe.js");
58
58
  const index_js_1 = require("../../reactjs/index.js");
59
- const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode = "iframe", ...props }) => {
59
+ const useIsInIframe_js_1 = require("../../shared/hooks/useIsInIframe.js");
60
+ const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode = "iframe", user, fetchUser, ...props }) => {
60
61
  const { iframeMode, resolvedConfig } = props;
61
62
  const { iframeRef } = (0, useIframe_js_1.useIframe)();
62
63
  const civicAuthConfig = (0, useCivicAuthConfig_js_1.useCivicAuthConfig)();
63
64
  const { challengeUrl } = resolvedConfig;
64
65
  const pkceConsumer = new PKCE_js_1.ConfidentialClientPKCEConsumer(challengeUrl);
66
+ const [isSigningOut, setIsSigningOut] = (0, react_1.useState)(false);
65
67
  const { data: session } = (0, index_js_1.useSession)();
66
- const { user } = (0, useUserCookie_js_1.useUserCookie)();
67
68
  const postSignOut = (0, react_1.useCallback)(async () => {
69
+ setIsSigningOut(true);
70
+ // user is signed out, manually update the user from cookies to not wait for polling
71
+ await fetchUser();
68
72
  await props?.onSignOut?.();
69
- }, [props]);
73
+ }, [fetchUser, props]);
74
+ (0, react_1.useEffect)(() => {
75
+ if (!session?.authenticated) {
76
+ setIsSigningOut(false);
77
+ }
78
+ }, [session?.authenticated]);
70
79
  const { signIn, signOut } = (0, useSignIn_js_1.useSignIn)({
71
80
  postSignOut,
72
81
  pkceConsumer,
@@ -83,19 +92,25 @@ const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode =
83
92
  return (react_1.default.createElement(TokenProvider_js_1.TokenProvider, null,
84
93
  react_1.default.createElement(UserProvider_js_1.UserProvider, { storage: new cookies_js_1.NextjsClientStorage(), user: user, signOut: signOut, signIn: signIn, displayMode: displayMode },
85
94
  react_1.default.createElement(IFrameAndLoading_js_1.IFrameAndLoading, { error: null, isLoading: isLoading, showIframeOnLogout: true }),
86
- isLoading && (react_1.default.createElement(BlockDisplay_js_1.BlockDisplay, null,
95
+ (isLoading || isSigningOut) && (react_1.default.createElement(BlockDisplay_js_1.BlockDisplay, null,
87
96
  react_1.default.createElement(LoadingIcon_js_1.LoadingIcon, null))),
88
97
  children)));
89
98
  };
90
99
  const CivicNextAuthProviderInternal = ({ children, ...props }) => {
91
- const isLoading = false;
92
- const { user, idToken } = (0, useUserCookie_js_1.useUserCookie)();
100
+ const isInIframe = (0, useIsInIframe_js_1.useIsInIframe)();
101
+ // if the SDK loads in an iframe, we show the loading spinner as the iframe
102
+ // will be waiting to be minimized
103
+ const isLoading = isInIframe;
104
+ const { user, idToken, fetchUser, isPending } = (0, useUserCookie_js_1.useUserCookie)();
105
+ (0, react_1.useEffect)(() => {
106
+ console.log("isPending", isPending);
107
+ }, [isPending]);
93
108
  const session = {
94
109
  authenticated: !!user,
95
110
  idToken,
96
111
  };
97
112
  return (react_1.default.createElement(SessionProvider_js_1.SessionProvider, { data: session, isLoading: isLoading },
98
- react_1.default.createElement(CivicNextAuthTokenProviderInternal, { ...props, isLoading: isLoading }, children)));
113
+ react_1.default.createElement(CivicNextAuthTokenProviderInternal, { ...props, user: user, idToken: idToken, fetchUser: fetchUser, isLoading: isLoading || isPending }, children)));
99
114
  };
100
115
  const CivicNextAuthProvider = ({ children, ...props }) => {
101
116
  const resolvedConfig = (0, config_js_1.resolveAuthConfig)();
@@ -1 +1 @@
1
- {"version":3,"file":"NextAuthProvider.js","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport {\n resolveAuthConfig,\n type AuthConfigWithDefaults,\n} from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { useUserCookie } from \"@/nextjs/hooks/useUserCookie.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport { BlockDisplay } from \"@/shared/components/BlockDisplay.js\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useSession } from \"@/reactjs/index.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\n\ntype CivicNextAuthTokenProviderInternalProps =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n };\ntype NextCivicAuthProviderInternalProps = Omit<\n AuthProviderProps,\n \"clientId\"\n> & {\n resolvedConfig: AuthConfigWithDefaults;\n};\ntype NextCivicAuthProviderProps = Omit<\n NextCivicAuthProviderInternalProps,\n \"clientId\" | \"resolvedConfig\" | \"redirectUrl\"\n>;\n\nconst CivicNextAuthTokenProviderInternal = ({\n children,\n isLoading,\n displayMode = \"iframe\",\n ...props\n}: CivicNextAuthTokenProviderInternalProps) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef } = useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(challengeUrl);\n const { data: session } = useSession();\n\n const { user } = useUserCookie();\n\n const postSignOut = useCallback(async () => {\n await props?.onSignOut?.();\n }, [props]);\n\n const { signIn, signOut } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n });\n\n useEffect(() => {\n if (\n iframeMode === \"embedded\" &&\n civicAuthConfig &&\n !session?.authenticated &&\n iframeRef?.current\n ) {\n signIn();\n }\n }, [iframeMode, civicAuthConfig, session?.authenticated, iframeRef, signIn]);\n\n return (\n <TokenProvider>\n <UserProvider\n storage={new NextjsClientStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n >\n <IFrameAndLoading\n error={null}\n isLoading={isLoading}\n showIframeOnLogout={true}\n />\n {isLoading && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {children}\n </UserProvider>\n </TokenProvider>\n );\n};\n\nconst CivicNextAuthProviderInternal = ({\n children,\n ...props\n}: NextCivicAuthProviderInternalProps) => {\n const isLoading = false;\n const { user, idToken } = useUserCookie();\n\n const session = {\n authenticated: !!user,\n idToken,\n };\n\n return (\n <SessionProvider data={session} isLoading={isLoading}>\n <CivicNextAuthTokenProviderInternal {...props} isLoading={isLoading}>\n {children}\n </CivicNextAuthTokenProviderInternal>\n </SessionProvider>\n );\n};\n\nconst CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const resolvedConfig = resolveAuthConfig();\n const {\n clientId,\n oauthServer,\n callbackUrl,\n challengeUrl,\n logoutUrl,\n logoutCallbackUrl,\n } = resolvedConfig;\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const appUrl = globalThis.window.location.origin;\n setRedirectUrl(resolveCallbackUrl(resolvedConfig, appUrl));\n }\n }, [callbackUrl, resolvedConfig]);\n\n return (\n <CivicAuthConfigProvider\n oauthServer={oauthServer}\n clientId={clientId}\n redirectUrl={redirectUrl}\n logoutRedirectUrl={logoutCallbackUrl}\n nonce={props?.nonce}\n challengeUrl={challengeUrl}\n logoutUrl={logoutUrl}\n logoutCallbackUrl={logoutCallbackUrl}\n >\n <IframeProvider iframeMode={props.iframeMode}>\n <CivicNextAuthProviderInternal\n {...props}\n resolvedConfig={resolvedConfig}\n >\n {children}\n </CivicNextAuthProviderInternal>\n </IframeProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicNextAuthProvider, type NextCivicAuthProviderProps };\n"]}
1
+ {"version":3,"file":"NextAuthProvider.js","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport {\n resolveAuthConfig,\n type AuthConfigWithDefaults,\n} from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { useUserCookie } from \"@/nextjs/hooks/useUserCookie.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport { BlockDisplay } from \"@/shared/components/BlockDisplay.js\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useSession } from \"@/reactjs/index.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport type { User } from \"@/types.js\";\n\ntype CivicNextAuthTokenProviderInternalProps =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n idToken?: string;\n user: User | null;\n fetchUser: () => Promise<void>;\n };\ntype NextCivicAuthProviderInternalProps = Omit<\n AuthProviderProps,\n \"clientId\"\n> & {\n resolvedConfig: AuthConfigWithDefaults;\n};\ntype NextCivicAuthProviderProps = Omit<\n NextCivicAuthProviderInternalProps,\n \"clientId\" | \"resolvedConfig\" | \"redirectUrl\"\n>;\n\nconst CivicNextAuthTokenProviderInternal = ({\n children,\n isLoading,\n displayMode = \"iframe\",\n user,\n fetchUser,\n ...props\n}: CivicNextAuthTokenProviderInternalProps) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef } = useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(challengeUrl);\n const [isSigningOut, setIsSigningOut] = useState(false);\n const { data: session } = useSession();\n\n const postSignOut = useCallback(async () => {\n setIsSigningOut(true);\n // user is signed out, manually update the user from cookies to not wait for polling\n await fetchUser();\n await props?.onSignOut?.();\n }, [fetchUser, props]);\n\n useEffect(() => {\n if (!session?.authenticated) {\n setIsSigningOut(false);\n }\n }, [session?.authenticated]);\n\n const { signIn, signOut } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n });\n\n useEffect(() => {\n if (\n iframeMode === \"embedded\" &&\n civicAuthConfig &&\n !session?.authenticated &&\n iframeRef?.current\n ) {\n signIn();\n }\n }, [iframeMode, civicAuthConfig, session?.authenticated, iframeRef, signIn]);\n\n return (\n <TokenProvider>\n <UserProvider\n storage={new NextjsClientStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n >\n <IFrameAndLoading\n error={null}\n isLoading={isLoading}\n showIframeOnLogout={true}\n />\n {(isLoading || isSigningOut) && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {children}\n </UserProvider>\n </TokenProvider>\n );\n};\n\nconst CivicNextAuthProviderInternal = ({\n children,\n ...props\n}: NextCivicAuthProviderInternalProps) => {\n const isInIframe = useIsInIframe();\n // if the SDK loads in an iframe, we show the loading spinner as the iframe\n // will be waiting to be minimized\n const isLoading = isInIframe;\n const { user, idToken, fetchUser, isPending } = useUserCookie();\n\n useEffect(() => {\n console.log(\"isPending\", isPending);\n }, [isPending]);\n\n const session = {\n authenticated: !!user,\n idToken,\n };\n\n return (\n <SessionProvider data={session} isLoading={isLoading}>\n <CivicNextAuthTokenProviderInternal\n {...props}\n user={user}\n idToken={idToken}\n fetchUser={fetchUser}\n isLoading={isLoading || isPending}\n >\n {children}\n </CivicNextAuthTokenProviderInternal>\n </SessionProvider>\n );\n};\n\nconst CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const resolvedConfig = resolveAuthConfig();\n const {\n clientId,\n oauthServer,\n callbackUrl,\n challengeUrl,\n logoutUrl,\n logoutCallbackUrl,\n } = resolvedConfig;\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const appUrl = globalThis.window.location.origin;\n setRedirectUrl(resolveCallbackUrl(resolvedConfig, appUrl));\n }\n }, [callbackUrl, resolvedConfig]);\n\n return (\n <CivicAuthConfigProvider\n oauthServer={oauthServer}\n clientId={clientId}\n redirectUrl={redirectUrl}\n logoutRedirectUrl={logoutCallbackUrl}\n nonce={props?.nonce}\n challengeUrl={challengeUrl}\n logoutUrl={logoutUrl}\n logoutCallbackUrl={logoutCallbackUrl}\n >\n <IframeProvider iframeMode={props.iframeMode}>\n <CivicNextAuthProviderInternal\n {...props}\n resolvedConfig={resolvedConfig}\n >\n {children}\n </CivicNextAuthProviderInternal>\n </IframeProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicNextAuthProvider, type NextCivicAuthProviderProps };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAarE,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG;IAC1D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,YAAY,8EAOf,yBAAyB,sBAsE3B,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAcrE,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG;IAC1D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,YAAY,8EAOf,yBAAyB,sBAyE3B,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -42,6 +42,7 @@ const useIframe_js_1 = require("../../shared/hooks/useIframe.js");
42
42
  const useCivicAuthConfig_js_1 = require("../../shared/hooks/useCivicAuthConfig.js");
43
43
  const useSession_js_1 = require("../../shared/hooks/useSession.js");
44
44
  const IFrameAndLoading_js_1 = require("../../shared/components/IFrameAndLoading.js");
45
+ const useIsInIframe_js_1 = require("../../shared/hooks/useIsInIframe.js");
45
46
  // Global this object setup
46
47
  let globalThisObject;
47
48
  if (typeof window !== "undefined") {
@@ -84,7 +85,10 @@ const AuthProvider = ({ children, onSignIn, onSignOut, pkceConsumer, iframeMode
84
85
  signIn();
85
86
  }
86
87
  }, [iframeMode, redirectUrl, isAuthenticated, iframeRef, signIn]);
87
- const isLoading = tokenExchangeInProgress || !authConfig;
88
+ const isInIframe = (0, useIsInIframe_js_1.useIsInIframe)();
89
+ // if the SDK loads in an iframe, we show the loading spinner as the iframe
90
+ // will be waiting to be minimized
91
+ const isLoading = tokenExchangeInProgress || !authConfig || isInIframe;
88
92
  const value = (0, react_1.useMemo)(() => ({
89
93
  isLoading,
90
94
  error: tokenExchangeError,
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.js","sourceRoot":"","sources":["../../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useEffect, useMemo, useState } from \"react\";\nimport type { SessionData } from \"@/types.js\";\nimport { AuthContext } from \"@/shared/providers/AuthContext.js\";\nimport type { PKCEConsumer } from \"@/services/types.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { useSession } from \"@/shared/hooks/useSession.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\n\n// Global this object setup\nlet globalThisObject;\nif (typeof window !== \"undefined\") {\n globalThisObject = window;\n} else if (typeof global !== \"undefined\") {\n globalThisObject = global;\n} else {\n globalThisObject = Function(\"return this\")();\n}\nglobalThisObject.globalThis = globalThisObject;\n\nexport type InternalAuthProviderProps = AuthProviderProps & {\n sessionData?: SessionData;\n pkceConsumer?: PKCEConsumer;\n};\n\nconst AuthProvider = ({\n children,\n onSignIn,\n onSignOut,\n pkceConsumer,\n iframeMode = \"modal\",\n displayMode = \"iframe\",\n}: InternalAuthProviderProps) => {\n const authConfig = useCivicAuthConfig();\n const { redirectUrl } = authConfig || {};\n const { iframeRef } = useIframe();\n\n const { signIn, signOut } = useSignIn({\n preSignOut: onSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const [localSessionData, setLocalSessionData] =\n useState<SessionData | null>();\n\n const {\n data: session,\n error: tokenExchangeError,\n isLoading: tokenExchangeInProgress,\n } = useSession();\n\n useEffect(() => {\n if (session) {\n setLocalSessionData(session);\n if (session.authenticated) {\n onSignIn?.();\n }\n }\n }, [onSignIn, session]);\n\n const isAuthenticated = useMemo(() => {\n return !!localSessionData?.idToken;\n }, [localSessionData]);\n\n useEffect(() => {\n if (\n iframeMode === \"embedded\" &&\n redirectUrl &&\n !isAuthenticated &&\n iframeRef?.current\n ) {\n signIn();\n }\n }, [iframeMode, redirectUrl, isAuthenticated, iframeRef, signIn]);\n\n const isLoading = tokenExchangeInProgress || !authConfig;\n const value = useMemo(\n () => ({\n isLoading,\n error: tokenExchangeError as Error | null,\n signOut,\n isAuthenticated,\n signIn,\n displayMode,\n }),\n [\n isLoading,\n tokenExchangeError,\n signOut,\n isAuthenticated,\n signIn,\n displayMode,\n ],\n );\n\n return (\n <AuthContext.Provider value={value}>\n <IFrameAndLoading error={tokenExchangeError} isLoading={isLoading} />\n {children}\n </AuthContext.Provider>\n );\n};\n\nexport { AuthProvider };\n"]}
1
+ {"version":3,"file":"AuthProvider.js","sourceRoot":"","sources":["../../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useEffect, useMemo, useState } from \"react\";\nimport type { SessionData } from \"@/types.js\";\nimport { AuthContext } from \"@/shared/providers/AuthContext.js\";\nimport type { PKCEConsumer } from \"@/services/types.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { useSession } from \"@/shared/hooks/useSession.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\n\n// Global this object setup\nlet globalThisObject;\nif (typeof window !== \"undefined\") {\n globalThisObject = window;\n} else if (typeof global !== \"undefined\") {\n globalThisObject = global;\n} else {\n globalThisObject = Function(\"return this\")();\n}\nglobalThisObject.globalThis = globalThisObject;\n\nexport type InternalAuthProviderProps = AuthProviderProps & {\n sessionData?: SessionData;\n pkceConsumer?: PKCEConsumer;\n};\n\nconst AuthProvider = ({\n children,\n onSignIn,\n onSignOut,\n pkceConsumer,\n iframeMode = \"modal\",\n displayMode = \"iframe\",\n}: InternalAuthProviderProps) => {\n const authConfig = useCivicAuthConfig();\n const { redirectUrl } = authConfig || {};\n const { iframeRef } = useIframe();\n\n const { signIn, signOut } = useSignIn({\n preSignOut: onSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const [localSessionData, setLocalSessionData] =\n useState<SessionData | null>();\n\n const {\n data: session,\n error: tokenExchangeError,\n isLoading: tokenExchangeInProgress,\n } = useSession();\n\n useEffect(() => {\n if (session) {\n setLocalSessionData(session);\n if (session.authenticated) {\n onSignIn?.();\n }\n }\n }, [onSignIn, session]);\n\n const isAuthenticated = useMemo(() => {\n return !!localSessionData?.idToken;\n }, [localSessionData]);\n\n useEffect(() => {\n if (\n iframeMode === \"embedded\" &&\n redirectUrl &&\n !isAuthenticated &&\n iframeRef?.current\n ) {\n signIn();\n }\n }, [iframeMode, redirectUrl, isAuthenticated, iframeRef, signIn]);\n\n const isInIframe = useIsInIframe();\n // if the SDK loads in an iframe, we show the loading spinner as the iframe\n // will be waiting to be minimized\n const isLoading = tokenExchangeInProgress || !authConfig || isInIframe;\n const value = useMemo(\n () => ({\n isLoading,\n error: tokenExchangeError as Error | null,\n signOut,\n isAuthenticated,\n signIn,\n displayMode,\n }),\n [\n isLoading,\n tokenExchangeError,\n signOut,\n isAuthenticated,\n signIn,\n displayMode,\n ],\n );\n\n return (\n <AuthContext.Provider value={value}>\n <IFrameAndLoading error={tokenExchangeError} isLoading={isLoading} />\n {children}\n </AuthContext.Provider>\n );\n};\n\nexport { AuthProvider };\n"]}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "@civic/auth:0.1.5-beta.1";
1
+ export declare const VERSION = "@civic/auth:0.1.5-beta.2";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -2,5 +2,5 @@
2
2
  // This is an auto-generated file. Do not edit.
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.VERSION = void 0;
5
- exports.VERSION = "@civic/auth:0.1.5-beta.1";
5
+ exports.VERSION = "@civic/auth:0.1.5-beta.2";
6
6
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/shared/version.ts"],"names":[],"mappings":";AAAA,+CAA+C;;;AAElC,QAAA,OAAO,GAAG,0BAA0B,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.1.5-beta.1\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/shared/version.ts"],"names":[],"mappings":";AAAA,+CAA+C;;;AAElC,QAAA,OAAO,GAAG,0BAA0B,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.1.5-beta.2\";\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function usePrevious<T>(value: T): T | undefined;
2
+ //# sourceMappingURL=usePrevious.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrevious.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/usePrevious.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,iBAMtC"}
@@ -0,0 +1,9 @@
1
+ import { useEffect, useRef } from "react";
2
+ export function usePrevious(value) {
3
+ const ref = useRef();
4
+ useEffect(() => {
5
+ ref.current = value;
6
+ }, [value]);
7
+ return ref.current;
8
+ }
9
+ //# sourceMappingURL=usePrevious.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrevious.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/usePrevious.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,UAAU,WAAW,CAAI,KAAQ;IACrC,MAAM,GAAG,GAAG,MAAM,EAAK,CAAC;IACxB,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACZ,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC","sourcesContent":["import { useEffect, useRef } from \"react\";\n\nexport function usePrevious<T>(value: T) {\n const ref = useRef<T>();\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"]}
@@ -2,5 +2,7 @@ import type { EmptyObject, User } from "../../types.js";
2
2
  export declare const useUserCookie: <T extends EmptyObject>() => {
3
3
  user: User<T> | null;
4
4
  idToken: string | undefined;
5
+ fetchUser: (abortController?: AbortController) => Promise<void>;
6
+ isPending: boolean;
5
7
  };
6
8
  //# sourceMappingURL=useUserCookie.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAqBpD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,WAAW;;;CAqDlD,CAAC"}
1
+ {"version":3,"file":"useUserCookie.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAuBpD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,WAAW;;;kCAatB,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC;;CAoE3D,CAAC"}
@@ -3,6 +3,8 @@ import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import { useRouter } from "next/navigation.js";
4
4
  import { getWindowCookieValue } from "../../lib/cookies.js";
5
5
  import { OAuthTokens, UserStorage } from "../../shared/lib/types.js";
6
+ import { usePrevious } from "./usePrevious.js";
7
+ import { useTransition } from "react";
6
8
  const getUserAndTokenFromCookie = () => getWindowCookieValue([
7
9
  {
8
10
  key: UserStorage.USER,
@@ -18,49 +20,68 @@ const getUserAndTokenFromCookie = () => getWindowCookieValue([
18
20
  export const useUserCookie = () => {
19
21
  const [user, setUser] = useState(null);
20
22
  const [idToken, setIdToken] = useState();
23
+ const [userChanged, setUserChanged] = useState(false);
21
24
  const hasRunRef = useRef(false);
25
+ const [isPending, startTransition] = useTransition();
22
26
  const router = useRouter();
27
+ const prevUser = usePrevious(user);
28
+ const prevPending = usePrevious(isPending);
23
29
  const fetchUser = useCallback(async (abortController) => {
24
- if (abortController.signal.aborted)
30
+ if (abortController?.signal.aborted)
25
31
  return;
26
- if (!hasRunRef.current) {
27
- const response = getUserAndTokenFromCookie() || {};
28
- const userData = response[UserStorage.USER];
29
- const tokenData = response[OAuthTokens.ID_TOKEN];
30
- if (abortController.signal.aborted)
31
- return;
32
- setIdToken(tokenData);
33
- setUser(userData || null);
34
- }
32
+ const response = getUserAndTokenFromCookie() || {};
33
+ const userData = response[UserStorage.USER];
34
+ const tokenData = response[OAuthTokens.ID_TOKEN];
35
+ if (abortController?.signal.aborted)
36
+ return;
37
+ setIdToken(tokenData);
38
+ setUser(userData || null);
35
39
  }, []);
40
+ // call fetch immediately after a refresh
36
41
  useEffect(() => {
37
- const abortController = new AbortController();
38
- const intervalId = setInterval(() => {
39
- fetchUser(abortController);
40
- }, 2000);
41
- const handleFocus = () => {
42
+ if (prevPending && !isPending) {
43
+ fetchUser();
44
+ }
45
+ }, [prevPending, isPending, fetchUser]);
46
+ useEffect(() => {
47
+ if (prevUser !== user) {
48
+ setUserChanged(true);
49
+ }
50
+ }, [user, prevUser]);
51
+ useEffect(() => {
52
+ let abortController = new AbortController();
53
+ const cookieListener = () => {
54
+ abortController = new AbortController();
42
55
  fetchUser(abortController);
43
56
  };
44
- window.addEventListener("focus", handleFocus);
45
- // call fetchUser on load to get initial user if present
57
+ document.addEventListener("visibilitychange", cookieListener);
58
+ window.addEventListener("storage", cookieListener);
59
+ window.addEventListener("focus", cookieListener);
46
60
  fetchUser(abortController);
61
+ const intervalId = setInterval(cookieListener, 2000);
47
62
  return () => {
48
63
  abortController.abort();
64
+ document.removeEventListener("visibilitychange", cookieListener);
65
+ window.removeEventListener("storage", cookieListener);
66
+ window.removeEventListener("focus", cookieListener);
49
67
  clearInterval(intervalId);
50
- window.removeEventListener("focus", handleFocus);
51
68
  };
52
69
  }, [fetchUser]);
53
70
  useEffect(() => {
54
- if (user) {
71
+ if (userChanged) {
55
72
  if (!hasRunRef.current) {
56
73
  hasRunRef.current = true;
57
- router.refresh();
74
+ setUserChanged(false);
75
+ startTransition(() => {
76
+ router.refresh();
77
+ });
58
78
  }
59
79
  }
60
80
  else {
61
81
  hasRunRef.current = false;
62
82
  }
63
- }, [user, router]);
64
- return { user, idToken };
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ }, [userChanged]);
85
+ return { user, idToken, fetchUser, isPending };
65
86
  };
66
87
  //# sourceMappingURL=useUserCookie.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { getWindowCookieValue } from \"@/lib/cookies.js\";\nimport type { EmptyObject, User } from \"@/types.js\";\nimport { OAuthTokens, UserStorage } from \"@/shared/lib/types.js\";\n\ntype UserAndTokenFromCookie = {\n [UserStorage.USER]: User | undefined;\n [OAuthTokens.ID_TOKEN]: string | undefined;\n};\nconst getUserAndTokenFromCookie = (): UserAndTokenFromCookie =>\n getWindowCookieValue([\n {\n key: UserStorage.USER,\n window: globalThis.window,\n parseJson: true,\n },\n {\n key: OAuthTokens.ID_TOKEN,\n window: globalThis.window,\n parseJson: false,\n },\n ]) as UserAndTokenFromCookie;\n\nexport const useUserCookie = <T extends EmptyObject>() => {\n const [user, setUser] = useState<User<T> | null>(null);\n const [idToken, setIdToken] = useState<string | undefined>();\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n const fetchUser = useCallback(async (abortController: AbortController) => {\n if (abortController.signal.aborted) return;\n if (!hasRunRef.current) {\n const response = getUserAndTokenFromCookie() || {};\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokens.ID_TOKEN];\n if (abortController.signal.aborted) return;\n\n setIdToken(tokenData);\n setUser(userData || null);\n }\n }, []);\n\n useEffect(() => {\n const abortController = new AbortController();\n const intervalId = setInterval(() => {\n fetchUser(abortController);\n }, 2000);\n\n const handleFocus = () => {\n fetchUser(abortController);\n };\n\n window.addEventListener(\"focus\", handleFocus);\n\n // call fetchUser on load to get initial user if present\n fetchUser(abortController);\n\n return () => {\n abortController.abort();\n clearInterval(intervalId);\n window.removeEventListener(\"focus\", handleFocus);\n };\n }, [fetchUser]);\n\n useEffect(() => {\n if (user) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n router.refresh();\n }\n } else {\n hasRunRef.current = false;\n }\n }, [user, router]);\n\n return { user, idToken };\n};\n"]}
1
+ {"version":3,"file":"useUserCookie.js","sourceRoot":"","sources":["../../../../src/nextjs/hooks/useUserCookie.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { getWindowCookieValue } from \"@/lib/cookies.js\";\nimport type { EmptyObject, User } from \"@/types.js\";\nimport { OAuthTokens, UserStorage } from \"@/shared/lib/types.js\";\nimport { usePrevious } from \"./usePrevious.js\";\nimport { useTransition } from \"react\";\n\ntype UserAndTokenFromCookie = {\n [UserStorage.USER]: User | undefined;\n [OAuthTokens.ID_TOKEN]: string | undefined;\n};\nconst getUserAndTokenFromCookie = (): UserAndTokenFromCookie =>\n getWindowCookieValue([\n {\n key: UserStorage.USER,\n window: globalThis.window,\n parseJson: true,\n },\n {\n key: OAuthTokens.ID_TOKEN,\n window: globalThis.window,\n parseJson: false,\n },\n ]) as UserAndTokenFromCookie;\n\nexport const useUserCookie = <T extends EmptyObject>() => {\n const [user, setUser] = useState<User<T> | null>(null);\n const [idToken, setIdToken] = useState<string | undefined>();\n const [userChanged, setUserChanged] = useState<boolean>(false);\n const hasRunRef = useRef(false);\n const [isPending, startTransition] = useTransition();\n\n const router = useRouter();\n\n const prevUser = usePrevious(user);\n const prevPending = usePrevious(isPending);\n\n const fetchUser = useCallback(\n async (abortController?: AbortController): Promise<void> => {\n if (abortController?.signal.aborted) return;\n\n const response = getUserAndTokenFromCookie() || {};\n const userData = response[UserStorage.USER] as User<T>;\n const tokenData = response[OAuthTokens.ID_TOKEN];\n\n if (abortController?.signal.aborted) return;\n\n setIdToken(tokenData);\n setUser(userData || null);\n },\n [],\n );\n\n // call fetch immediately after a refresh\n useEffect(() => {\n if (prevPending && !isPending) {\n fetchUser();\n }\n }, [prevPending, isPending, fetchUser]);\n\n useEffect(() => {\n if (prevUser !== user) {\n setUserChanged(true);\n }\n }, [user, prevUser]);\n\n useEffect(() => {\n let abortController = new AbortController();\n const cookieListener = () => {\n abortController = new AbortController();\n fetchUser(abortController);\n };\n\n document.addEventListener(\"visibilitychange\", cookieListener);\n window.addEventListener(\"storage\", cookieListener);\n window.addEventListener(\"focus\", cookieListener);\n\n fetchUser(abortController);\n\n const intervalId = setInterval(cookieListener, 2000);\n\n return () => {\n abortController.abort();\n document.removeEventListener(\"visibilitychange\", cookieListener);\n window.removeEventListener(\"storage\", cookieListener);\n window.removeEventListener(\"focus\", cookieListener);\n clearInterval(intervalId);\n };\n }, [fetchUser]);\n\n useEffect(() => {\n if (userChanged) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n setUserChanged(false);\n startTransition(() => {\n router.refresh();\n });\n }\n } else {\n hasRunRef.current = false;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [userChanged]);\n\n return { user, idToken, fetchUser, isPending };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AACA;;GAEG;AACH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAiB5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAMrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;AAoFF,QAAA,MAAM,qBAAqB,2BAGxB,0BAA0B,sBAwC5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
1
+ {"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AACA;;GAEG;AACH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAiB5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAWrE,KAAK,kCAAkC,GAAG,IAAI,CAC5C,iBAAiB,EACjB,UAAU,CACX,GAAG;IACF,cAAc,EAAE,sBAAsB,CAAC;CACxC,CAAC;AACF,KAAK,0BAA0B,GAAG,IAAI,CACpC,kCAAkC,EAClC,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAC9C,CAAC;AA2GF,QAAA,MAAM,qBAAqB,2BAGxB,0BAA0B,sBAwC5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
@@ -20,17 +20,26 @@ import { BlockDisplay } from "../../shared/components/BlockDisplay.js";
20
20
  import { LoadingIcon } from "../../shared/components/LoadingIcon.js";
21
21
  import { useIframe } from "../../shared/hooks/useIframe.js";
22
22
  import { useSession } from "../../reactjs/index.js";
23
- const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode = "iframe", ...props }) => {
23
+ import { useIsInIframe } from "../../shared/hooks/useIsInIframe.js";
24
+ const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode = "iframe", user, fetchUser, ...props }) => {
24
25
  const { iframeMode, resolvedConfig } = props;
25
26
  const { iframeRef } = useIframe();
26
27
  const civicAuthConfig = useCivicAuthConfig();
27
28
  const { challengeUrl } = resolvedConfig;
28
29
  const pkceConsumer = new ConfidentialClientPKCEConsumer(challengeUrl);
30
+ const [isSigningOut, setIsSigningOut] = useState(false);
29
31
  const { data: session } = useSession();
30
- const { user } = useUserCookie();
31
32
  const postSignOut = useCallback(async () => {
33
+ setIsSigningOut(true);
34
+ // user is signed out, manually update the user from cookies to not wait for polling
35
+ await fetchUser();
32
36
  await props?.onSignOut?.();
33
- }, [props]);
37
+ }, [fetchUser, props]);
38
+ useEffect(() => {
39
+ if (!session?.authenticated) {
40
+ setIsSigningOut(false);
41
+ }
42
+ }, [session?.authenticated]);
34
43
  const { signIn, signOut } = useSignIn({
35
44
  postSignOut,
36
45
  pkceConsumer,
@@ -47,19 +56,25 @@ const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode =
47
56
  return (React.createElement(TokenProvider, null,
48
57
  React.createElement(UserProvider, { storage: new NextjsClientStorage(), user: user, signOut: signOut, signIn: signIn, displayMode: displayMode },
49
58
  React.createElement(IFrameAndLoading, { error: null, isLoading: isLoading, showIframeOnLogout: true }),
50
- isLoading && (React.createElement(BlockDisplay, null,
59
+ (isLoading || isSigningOut) && (React.createElement(BlockDisplay, null,
51
60
  React.createElement(LoadingIcon, null))),
52
61
  children)));
53
62
  };
54
63
  const CivicNextAuthProviderInternal = ({ children, ...props }) => {
55
- const isLoading = false;
56
- const { user, idToken } = useUserCookie();
64
+ const isInIframe = useIsInIframe();
65
+ // if the SDK loads in an iframe, we show the loading spinner as the iframe
66
+ // will be waiting to be minimized
67
+ const isLoading = isInIframe;
68
+ const { user, idToken, fetchUser, isPending } = useUserCookie();
69
+ useEffect(() => {
70
+ console.log("isPending", isPending);
71
+ }, [isPending]);
57
72
  const session = {
58
73
  authenticated: !!user,
59
74
  idToken,
60
75
  };
61
76
  return (React.createElement(SessionProvider, { data: session, isLoading: isLoading },
62
- React.createElement(CivicNextAuthTokenProviderInternal, { ...props, isLoading: isLoading }, children)));
77
+ React.createElement(CivicNextAuthTokenProviderInternal, { ...props, user: user, idToken: idToken, fetchUser: fetchUser, isLoading: isLoading || isPending }, children)));
63
78
  };
64
79
  const CivicNextAuthProvider = ({ children, ...props }) => {
65
80
  const resolvedConfig = resolveAuthConfig();