@civic/auth 0.4.6 → 0.4.7

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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/lib/windowUtil.d.ts +13 -0
  3. package/dist/lib/windowUtil.d.ts.map +1 -1
  4. package/dist/lib/windowUtil.js +33 -10
  5. package/dist/lib/windowUtil.js.map +1 -1
  6. package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  7. package/dist/nextjs/providers/NextAuthProvider.js +2 -1
  8. package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
  9. package/dist/reactjs/providers/AuthProvider.d.ts.map +1 -1
  10. package/dist/reactjs/providers/AuthProvider.js +5 -3
  11. package/dist/reactjs/providers/AuthProvider.js.map +1 -1
  12. package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
  13. package/dist/reactjs/providers/CivicAuthProvider.js +2 -1
  14. package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
  15. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts.map +1 -1
  16. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js +0 -4
  17. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js.map +1 -1
  18. package/dist/shared/hooks/index.d.ts +1 -0
  19. package/dist/shared/hooks/index.d.ts.map +1 -1
  20. package/dist/shared/hooks/index.js +1 -0
  21. package/dist/shared/hooks/index.js.map +1 -1
  22. package/dist/shared/hooks/useIsInIframe.d.ts +4 -0
  23. package/dist/shared/hooks/useIsInIframe.d.ts.map +1 -1
  24. package/dist/shared/hooks/useIsInIframe.js +11 -2
  25. package/dist/shared/hooks/useIsInIframe.js.map +1 -1
  26. package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
  27. package/dist/shared/hooks/useSignIn.js +64 -4
  28. package/dist/shared/hooks/useSignIn.js.map +1 -1
  29. package/dist/shared/providers/AuthStatusContext.d.ts +12 -0
  30. package/dist/shared/providers/AuthStatusContext.d.ts.map +1 -0
  31. package/dist/shared/providers/AuthStatusContext.js +17 -0
  32. package/dist/shared/providers/AuthStatusContext.js.map +1 -0
  33. package/dist/shared/version.d.ts +1 -1
  34. package/dist/shared/version.js +1 -1
  35. package/dist/shared/version.js.map +1 -1
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 0.4.7 Standalone react fixes
2
+ - Fix case where standalone react app isn't recognising existing session
3
+ - Fix react standalone case where it's initiating startSignIn twice leading to duplicate calls to the auth-server
4
+ - Add refresh timeout in useSignIn for initial signIn call so that the code-verifier doesn't get stale if the user leaves the tab open on a page and doesn't sign in right away
5
+
6
+ # 0.4.6 Refresh fixes
7
+ - if a valid refresh token exists, automatically try to re-hydrate the user's session by doing an oauth refresh
8
+
1
9
  # 0.4.5 Block display fix
2
10
  - if the iframe has already been used on a page and it's re-opened we shouldn't show the previous app content
3
11
 
@@ -1,3 +1,16 @@
1
+ /**
2
+ * Extend the Window interface to include Cypress
3
+ */
4
+ declare global {
5
+ interface Window {
6
+ Cypress?: unknown;
7
+ }
8
+ }
9
+ /**
10
+ * Detects if the current window is running inside an iframe
11
+ * Uses multiple methods to improve detection reliability
12
+ * If detected as iframe, adds an immediate style blocker to prevent content flashes
13
+ */
1
14
  declare const isWindowInIframe: (window: Window) => boolean;
2
15
  declare const removeParamsWithoutReload: (paramsToRemove: string[]) => void;
3
16
  export { isWindowInIframe, removeParamsWithoutReload };
@@ -1 +1 @@
1
- {"version":3,"file":"windowUtil.d.ts","sourceRoot":"","sources":["../../src/lib/windowUtil.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,OAa1C,CAAC;AAEF,QAAA,MAAM,yBAAyB,GAAI,gBAAgB,MAAM,EAAE,SAW1D,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,CAAC"}
1
+ {"version":3,"file":"windowUtil.d.ts","sourceRoot":"","sources":["../../src/lib/windowUtil.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB;CACF;AAED;;;;GAIG;AACH,QAAA,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,OAuC1C,CAAC;AAEF,QAAA,MAAM,yBAAyB,GAAI,gBAAgB,MAAM,EAAE,SAW1D,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,CAAC"}
@@ -1,17 +1,40 @@
1
+ /**
2
+ * Detects if the current window is running inside an iframe
3
+ * Uses multiple methods to improve detection reliability
4
+ * If detected as iframe, adds an immediate style blocker to prevent content flashes
5
+ */
1
6
  const isWindowInIframe = (window) => {
2
- if (typeof window !== "undefined") {
3
- try {
4
- if (window?.frameElement?.id === "civic-auth-iframe") {
5
- return true;
6
- }
7
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
7
+ // Make sure we're in a browser environment
8
+ if (typeof window === "undefined") {
9
+ return false;
10
+ }
11
+ // Check if running in Cypress
12
+ const isCypress = Boolean(window.Cypress || window.parent?.Cypress || window.top?.Cypress);
13
+ // If we're in Cypress, don't treat it as an iframe
14
+ if (isCypress) {
15
+ return false;
16
+ }
17
+ let isInIframe = false;
18
+ try {
19
+ // Method 1: Check for frameElement
20
+ // This can throw a cross-origin error, but works reliably for same-origin frames
21
+ if (window.frameElement !== null) {
22
+ isInIframe = true;
8
23
  }
9
- catch (_e) {
10
- // If we get an error, we're not in an iframe
11
- return false;
24
+ // Method 2: Check specifically for our civic auth iframe
25
+ // Use explicit type assertion to handle the TypeScript issue
26
+ const frameEl = window.frameElement;
27
+ if (frameEl && frameEl.id === "civic-auth-iframe") {
28
+ isInIframe = true;
12
29
  }
13
30
  }
14
- return false;
31
+ catch {
32
+ // If we get a security/cross-origin error, it's likely because
33
+ // we're in an iframe from a different origin
34
+ // So this is actually a positive signal that we're in an iframe
35
+ isInIframe = true;
36
+ }
37
+ return isInIframe;
15
38
  };
16
39
  const removeParamsWithoutReload = (paramsToRemove) => {
17
40
  const url = new URL(window.location.href);
@@ -1 +1 @@
1
- {"version":3,"file":"windowUtil.js","sourceRoot":"","sources":["../../src/lib/windowUtil.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAW,EAAE;IACnD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,IAAI,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,mBAAmB,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,6DAA6D;QAC/D,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACZ,6CAA6C;YAC7C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAAC,cAAwB,EAAE,EAAE;IAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,OAAO,CAAC,CAAC,KAAa,EAAE,EAAE;QACvC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,CAAC","sourcesContent":["const isWindowInIframe = (window: Window): boolean => {\n if (typeof window !== \"undefined\") {\n try {\n if (window?.frameElement?.id === \"civic-auth-iframe\") {\n return true;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_e) {\n // If we get an error, we're not in an iframe\n return false;\n }\n }\n return false;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n try {\n window.history.replaceState({}, \"\", url);\n window.dispatchEvent(new Event(\"popstate\"));\n } catch (error) {\n console.warn(\"window.history.replaceState failed\", error);\n }\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n"]}
1
+ {"version":3,"file":"windowUtil.js","sourceRoot":"","sources":["../../src/lib/windowUtil.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAW,EAAE;IACnD,2CAA2C;IAC3C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8BAA8B;IAC9B,MAAM,SAAS,GAAG,OAAO,CACvB,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,EAAE,OAAO,CAChE,CAAC;IAEF,mDAAmD;IACnD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,IAAI,CAAC;QACH,mCAAmC;QACnC,iFAAiF;QACjF,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YACjC,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;QAED,yDAAyD;QACzD,6DAA6D;QAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,YAAkC,CAAC;QAC1D,IAAI,OAAO,IAAI,OAAO,CAAC,EAAE,KAAK,mBAAmB,EAAE,CAAC;YAClD,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,6CAA6C;QAC7C,gEAAgE;QAChE,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAAC,cAAwB,EAAE,EAAE;IAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,OAAO,CAAC,CAAC,KAAa,EAAE,EAAE;QACvC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,CAAC","sourcesContent":["/**\n * Extend the Window interface to include Cypress\n */\ndeclare global {\n interface Window {\n Cypress?: unknown;\n }\n}\n\n/**\n * Detects if the current window is running inside an iframe\n * Uses multiple methods to improve detection reliability\n * If detected as iframe, adds an immediate style blocker to prevent content flashes\n */\nconst isWindowInIframe = (window: Window): boolean => {\n // Make sure we're in a browser environment\n if (typeof window === \"undefined\") {\n return false;\n }\n\n // Check if running in Cypress\n const isCypress = Boolean(\n window.Cypress || window.parent?.Cypress || window.top?.Cypress,\n );\n\n // If we're in Cypress, don't treat it as an iframe\n if (isCypress) {\n return false;\n }\n\n let isInIframe = false;\n\n try {\n // Method 1: Check for frameElement\n // This can throw a cross-origin error, but works reliably for same-origin frames\n if (window.frameElement !== null) {\n isInIframe = true;\n }\n\n // Method 2: Check specifically for our civic auth iframe\n // Use explicit type assertion to handle the TypeScript issue\n const frameEl = window.frameElement as HTMLElement | null;\n if (frameEl && frameEl.id === \"civic-auth-iframe\") {\n isInIframe = true;\n }\n } catch {\n // If we get a security/cross-origin error, it's likely because\n // we're in an iframe from a different origin\n // So this is actually a positive signal that we're in an iframe\n isInIframe = true;\n }\n\n return isInIframe;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n try {\n window.history.replaceState({}, \"\", url);\n window.dispatchEvent(new Event(\"popstate\"));\n } catch (error) {\n console.warn(\"window.history.replaceState failed\", error);\n }\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"NextAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/nextjs/providers/NextAuthProvider.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAerE,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;AAgIF,QAAA,MAAM,qBAAqB,GAAI,wBAG5B,0BAA0B,qDA0C5B,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":"AAKA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAgBrE,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;AAgIF,QAAA,MAAM,qBAAqB,GAAI,wBAG5B,0BAA0B,qDA4C5B,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,CAAC"}
@@ -25,6 +25,7 @@ import { useRefresh } from "../../nextjs/hooks/useRefresh.js";
25
25
  import { useCurrentUrl, useSession } from "../../shared/hooks/index.js";
26
26
  import { BrowserCookieStorage } from "../../shared/index.js";
27
27
  import { getIframeRef } from "../../shared/lib/iframeUtils.js";
28
+ import { AuthStatusProvider } from "../../shared/providers/AuthStatusContext.js";
28
29
  const CivicNextAuthTokenProviderInternal = ({ children, isLoading, displayMode = "iframe", user, fetchUser, ...props }) => {
29
30
  const { iframeMode, resolvedConfig } = props;
30
31
  const { iframeRef, setIframeIsVisible, isIframeMounted, setIframeMounted } = useIframe();
@@ -104,7 +105,7 @@ const CivicNextAuthProvider = ({ children, ...props }) => {
104
105
  setRedirectUrl(resolveCallbackUrl(resolvedConfig, appUrl));
105
106
  }
106
107
  }, [callbackUrl, resolvedConfig]);
107
- return (_jsx(CivicAuthConfigProvider, { oauthServer: oauthServer, clientId: clientId, redirectUrl: redirectUrl, logoutRedirectUrl: logoutCallbackUrl, nonce: props?.nonce, challengeUrl: challengeUrl, refreshUrl: refreshUrl, logoutUrl: logoutUrl, logoutCallbackUrl: logoutCallbackUrl, children: _jsx(IframeProvider, { iframeMode: props.iframeMode, children: _jsx(CivicNextAuthProviderInternal, { ...props, resolvedConfig: resolvedConfig, children: children }) }) }));
108
+ return (_jsx(CivicAuthConfigProvider, { oauthServer: oauthServer, clientId: clientId, redirectUrl: redirectUrl, logoutRedirectUrl: logoutCallbackUrl, nonce: props?.nonce, challengeUrl: challengeUrl, refreshUrl: refreshUrl, logoutUrl: logoutUrl, logoutCallbackUrl: logoutCallbackUrl, children: _jsx(AuthStatusProvider, { children: _jsx(IframeProvider, { iframeMode: props.iframeMode, children: _jsx(CivicNextAuthProviderInternal, { ...props, resolvedConfig: resolvedConfig, children: children }) }) }) }));
108
109
  };
109
110
  export { CivicNextAuthProvider };
110
111
  //# sourceMappingURL=NextAuthProvider.js.map
@@ -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 { 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 type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport { AuthStatus, type UnknownObject, type User } from \"@/types.js\";\nimport { useRefresh } from \"@/nextjs/hooks/useRefresh.js\";\nimport { useCurrentUrl, useSession } from \"@/shared/hooks/index.js\";\nimport { BrowserCookieStorage } from \"@/shared/index.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\n\ntype CivicNextAuthTokenProviderInternalProps<TUser extends UnknownObject> =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n idToken?: string;\n user: User<TUser> | 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 TUser extends UnknownObject = UnknownObject,\n>({\n children,\n isLoading,\n displayMode = \"iframe\",\n user,\n fetchUser,\n ...props\n}: CivicNextAuthTokenProviderInternalProps<TUser>) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef, setIframeIsVisible, isIframeMounted, setIframeMounted } =\n useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(challengeUrl);\n const { data: session } = useSession();\n const currentUrl = useCurrentUrl();\n\n useEffect(() => {\n if (session?.authenticated) {\n setIframeMounted(false);\n // the session is authenticated, so don't show the login iframe\n setIframeIsVisible(false);\n return;\n }\n }, [session?.authenticated, setIframeIsVisible, setIframeMounted]);\n\n const postSignOut = useCallback(async () => {\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 const { signIn, startSignIn, signOut, authStatus } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const { error: refreshError } = useRefresh();\n\n useEffect(() => {\n const ref = getIframeRef(iframeRef?.current, true);\n if (\n isIframeMounted &&\n civicAuthConfig &&\n !session?.authenticated &&\n ref &&\n authStatus === AuthStatus.UNAUTHENTICATED &&\n displayMode === \"iframe\" &&\n !currentUrl?.includes(\"code=\")\n ) {\n startSignIn();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n isIframeMounted,\n currentUrl,\n iframeMode,\n iframeRef,\n civicAuthConfig,\n session?.authenticated,\n authStatus,\n startSignIn,\n displayMode,\n ]);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signing out...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n return (\n <TokenProvider>\n <UserProvider\n storage={new BrowserCookieStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n authStatus={authStatus}\n >\n <IFrameAndLoading error={null} isLoading={isLoading} />\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 // 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 = useIsInIframe();\n const { user, idToken, fetchUser } = useUserCookie();\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}\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 refreshUrl,\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 refreshUrl={refreshUrl}\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 { 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 type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport { AuthStatus, type UnknownObject, type User } from \"@/types.js\";\nimport { useRefresh } from \"@/nextjs/hooks/useRefresh.js\";\nimport { useCurrentUrl, useSession } from \"@/shared/hooks/index.js\";\nimport { BrowserCookieStorage } from \"@/shared/index.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\nimport { AuthStatusProvider } from \"@/shared/providers/AuthStatusContext.js\";\n\ntype CivicNextAuthTokenProviderInternalProps<TUser extends UnknownObject> =\n NextCivicAuthProviderInternalProps & {\n isLoading: boolean;\n idToken?: string;\n user: User<TUser> | 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 TUser extends UnknownObject = UnknownObject,\n>({\n children,\n isLoading,\n displayMode = \"iframe\",\n user,\n fetchUser,\n ...props\n}: CivicNextAuthTokenProviderInternalProps<TUser>) => {\n const { iframeMode, resolvedConfig } = props;\n const { iframeRef, setIframeIsVisible, isIframeMounted, setIframeMounted } =\n useIframe();\n const civicAuthConfig = useCivicAuthConfig();\n const { challengeUrl } = resolvedConfig;\n const pkceConsumer = new ConfidentialClientPKCEConsumer(challengeUrl);\n const { data: session } = useSession();\n const currentUrl = useCurrentUrl();\n\n useEffect(() => {\n if (session?.authenticated) {\n setIframeMounted(false);\n // the session is authenticated, so don't show the login iframe\n setIframeIsVisible(false);\n return;\n }\n }, [session?.authenticated, setIframeIsVisible, setIframeMounted]);\n\n const postSignOut = useCallback(async () => {\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 const { signIn, startSignIn, signOut, authStatus } = useSignIn({\n postSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const { error: refreshError } = useRefresh();\n\n useEffect(() => {\n const ref = getIframeRef(iframeRef?.current, true);\n if (\n isIframeMounted &&\n civicAuthConfig &&\n !session?.authenticated &&\n ref &&\n authStatus === AuthStatus.UNAUTHENTICATED &&\n displayMode === \"iframe\" &&\n !currentUrl?.includes(\"code=\")\n ) {\n startSignIn();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n isIframeMounted,\n currentUrl,\n iframeMode,\n iframeRef,\n civicAuthConfig,\n session?.authenticated,\n authStatus,\n startSignIn,\n displayMode,\n ]);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signing out...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n return (\n <TokenProvider>\n <UserProvider\n storage={new BrowserCookieStorage()}\n user={user}\n signOut={signOut}\n signIn={signIn}\n displayMode={displayMode}\n authStatus={authStatus}\n >\n <IFrameAndLoading error={null} isLoading={isLoading} />\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 // 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 = useIsInIframe();\n const { user, idToken, fetchUser } = useUserCookie();\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}\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 refreshUrl,\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 refreshUrl={refreshUrl}\n logoutUrl={logoutUrl}\n logoutCallbackUrl={logoutCallbackUrl}\n >\n <AuthStatusProvider>\n <IframeProvider iframeMode={props.iframeMode}>\n <CivicNextAuthProviderInternal\n {...props}\n resolvedConfig={resolvedConfig}\n >\n {children}\n </CivicNextAuthProviderInternal>\n </IframeProvider>\n </AuthStatusProvider>\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":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAerE,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG;IAC1D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,YAAY,GAAI,+DAMnB,yBAAyB,qDA0E3B,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAerE,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG;IAC1D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,QAAA,MAAM,YAAY,GAAI,+DAMnB,yBAAyB,qDA6E3B,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -44,9 +44,11 @@ const AuthProvider = ({ children, onSignIn, onSignOut, pkceConsumer, displayMode
44
44
  // The startSignIn functionality has been moved to ClientTokenExchangeSessionProvider
45
45
  // to prevent race conditions with validateExistingSession
46
46
  const isInIframe = useIsInIframe();
47
- // if the SDK loads in an iframe, we show the loading spinner as the iframe
48
- // will be waiting to be minimized
49
- const isLoading = tokenExchangeInProgress || !authConfig || isInIframe;
47
+ // if the SDK loads in an iframe, we show the loading spinner until we know the auth state
48
+ // but don't keep showing it indefinitely if it's just the isInIframe status
49
+ const isLoading = tokenExchangeInProgress ||
50
+ !authConfig ||
51
+ (isInIframe && !localSessionData?.authenticated);
50
52
  const { error: refreshError } = useRefresh(session);
51
53
  useEffect(() => {
52
54
  if (refreshError) {
@@ -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 { 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\";\nimport { useRefresh } from \"@/shared/hooks/useRefresh.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 displayMode = \"iframe\",\n}: InternalAuthProviderProps) => {\n const authConfig = useCivicAuthConfig();\n const { signIn, signOut, authStatus } = 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 // The startSignIn functionality has been moved to ClientTokenExchangeSessionProvider\n // to prevent race conditions with validateExistingSession\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\n const { error: refreshError } = useRefresh(session);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signingOut...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n const value = useMemo(\n () => ({\n isLoading,\n error: tokenExchangeError as Error | null,\n signOut,\n authStatus,\n isAuthenticated,\n signIn,\n displayMode,\n }),\n [\n isLoading,\n tokenExchangeError,\n signOut,\n authStatus,\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 { 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\";\nimport { useRefresh } from \"@/shared/hooks/useRefresh.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 displayMode = \"iframe\",\n}: InternalAuthProviderProps) => {\n const authConfig = useCivicAuthConfig();\n const { signIn, signOut, authStatus } = 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 // The startSignIn functionality has been moved to ClientTokenExchangeSessionProvider\n // to prevent race conditions with validateExistingSession\n\n const isInIframe = useIsInIframe();\n // if the SDK loads in an iframe, we show the loading spinner until we know the auth state\n // but don't keep showing it indefinitely if it's just the isInIframe status\n const isLoading =\n tokenExchangeInProgress ||\n !authConfig ||\n (isInIframe && !localSessionData?.authenticated);\n\n const { error: refreshError } = useRefresh(session);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signingOut...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n const value = useMemo(\n () => ({\n isLoading,\n error: tokenExchangeError as Error | null,\n signOut,\n authStatus,\n isAuthenticated,\n signIn,\n displayMode,\n }),\n [\n isLoading,\n tokenExchangeError,\n signOut,\n authStatus,\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 +1 @@
1
- {"version":3,"file":"CivicAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,KAAK,sBAAsB,GAAG,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;AAmCtE,QAAA,MAAM,iBAAiB,GAAI,wBAAwB,sBAAsB,qDAmBxE,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"CivicAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,KAAK,sBAAsB,GAAG,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;AAmCtE,QAAA,MAAM,iBAAiB,GAAI,wBAAwB,sBAAsB,qDAqBxE,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,CAAC"}
@@ -12,6 +12,7 @@ import { SessionProvider } from "../../shared/providers/SessionProvider.js";
12
12
  import { useClientTokenExchangeSession } from "../../reactjs/hooks/useClientTokenExchangeSession.js";
13
13
  import { TokenProvider } from "../../shared/providers/TokenProvider.js";
14
14
  import { useAuth } from "../../shared/hooks/useAuth.js";
15
+ import { AuthStatusProvider } from "../../shared/providers/AuthStatusContext.js";
15
16
  const WrapperUserProvider = ({ children }) => {
16
17
  const { signIn, signOut, displayMode, authStatus } = useAuth();
17
18
  return (_jsx(UserProvider, { storage: new LocalStorageAdapter(), signIn: signIn, signOut: signOut, user: null, authStatus: authStatus, displayMode: displayMode, children: children }));
@@ -21,7 +22,7 @@ const WrapperSessionAuthProvider = ({ children, ...props }) => {
21
22
  return (_jsx(SessionProvider, { ...sessionData, children: _jsx(AuthProvider, { ...props, pkceConsumer: new BrowserPublicClientPKCEProducer(), children: _jsx(TokenProvider, { children: _jsx(WrapperUserProvider, { children: children }) }) }) }));
22
23
  };
23
24
  const CivicAuthProvider = ({ children, ...props }) => {
24
- return (_jsx(CivicAuthConfigProvider, { oauthServer: props?.config?.oauthServer, clientId: props?.clientId, redirectUrl: props?.redirectUrl, nonce: props?.nonce, logoutRedirectUrl: props?.logoutRedirectUrl, displayMode: props?.displayMode, children: _jsx(IframeProvider, { iframeMode: props.iframeMode, children: _jsx(ClientTokenExchangeSessionProvider, { children: _jsx(WrapperSessionAuthProvider, { ...props, children: children }) }) }) }));
25
+ return (_jsx(CivicAuthConfigProvider, { oauthServer: props?.config?.oauthServer, clientId: props?.clientId, redirectUrl: props?.redirectUrl, nonce: props?.nonce, logoutRedirectUrl: props?.logoutRedirectUrl, displayMode: props?.displayMode, children: _jsx(AuthStatusProvider, { children: _jsx(IframeProvider, { iframeMode: props.iframeMode, children: _jsx(ClientTokenExchangeSessionProvider, { children: _jsx(WrapperSessionAuthProvider, { ...props, children: children }) }) }) }) }));
25
26
  };
26
27
  export { CivicAuthProvider };
27
28
  //# sourceMappingURL=CivicAuthProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,kCAAkC,EAAE,MAAM,2DAA2D,CAAC;AAC/G,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAKpD,MAAM,mBAAmB,GAAG,CAAC,EAAE,QAAQ,EAAiC,EAAE,EAAE;IAC1E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAAC;IAC/D,OAAO,CACL,KAAC,YAAY,IACX,OAAO,EAAE,IAAI,mBAAmB,EAAE,EAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,YAEvB,QAAQ,GACI,CAChB,CAAC;AACJ,CAAC,CAAC;AACF,MAAM,0BAA0B,GAAG,CAAC,EAClC,QAAQ,EACR,GAAG,KAAK,EACe,EAAE,EAAE;IAC3B,MAAM,WAAW,GAAG,6BAA6B,EAAE,CAAC;IACpD,OAAO,CACL,KAAC,eAAe,OAAK,WAAW,YAC9B,KAAC,YAAY,OACP,KAAK,EACT,YAAY,EAAE,IAAI,+BAA+B,EAAE,YAEnD,KAAC,aAAa,cACZ,KAAC,mBAAmB,cAAE,QAAQ,GAAuB,GACvC,GACH,GACC,CACnB,CAAC;AACJ,CAAC,CAAC;AACF,MAAM,iBAAiB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAA0B,EAAE,EAAE;IAC3E,OAAO,CACL,KAAC,uBAAuB,IACtB,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EACvC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EACzB,WAAW,EAAE,KAAK,EAAE,WAAW,EAC/B,KAAK,EAAE,KAAK,EAAE,KAAK,EACnB,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAC3C,WAAW,EAAE,KAAK,EAAE,WAAW,YAE/B,KAAC,cAAc,IAAC,UAAU,EAAE,KAAK,CAAC,UAAU,YAC1C,KAAC,kCAAkC,cACjC,KAAC,0BAA0B,OAAK,KAAK,YAClC,QAAQ,GACkB,GACM,GACtB,GACO,CAC3B,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAA+B,CAAC","sourcesContent":["\"use client\";\nimport React from \"react\";\nimport { AuthProvider } from \"@/reactjs/providers/AuthProvider.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { ClientTokenExchangeSessionProvider } from \"@/reactjs/providers/ClientTokenExchangeSessionProvider.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { useClientTokenExchangeSession } from \"@/reactjs/hooks/useClientTokenExchangeSession.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useAuth } from \"@/shared/hooks/useAuth.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\n\ntype CivicAuthProviderProps = Omit<AuthProviderProps, \"pkceConsumer\">;\n\nconst WrapperUserProvider = ({ children }: { children: React.ReactNode }) => {\n const { signIn, signOut, displayMode, authStatus } = useAuth();\n return (\n <UserProvider\n storage={new LocalStorageAdapter()}\n signIn={signIn}\n signOut={signOut}\n user={null}\n authStatus={authStatus}\n displayMode={displayMode}\n >\n {children}\n </UserProvider>\n );\n};\nconst WrapperSessionAuthProvider = ({\n children,\n ...props\n}: CivicAuthProviderProps) => {\n const sessionData = useClientTokenExchangeSession();\n return (\n <SessionProvider {...sessionData}>\n <AuthProvider\n {...props}\n pkceConsumer={new BrowserPublicClientPKCEProducer()}\n >\n <TokenProvider>\n <WrapperUserProvider>{children}</WrapperUserProvider>\n </TokenProvider>\n </AuthProvider>\n </SessionProvider>\n );\n};\nconst CivicAuthProvider = ({ children, ...props }: CivicAuthProviderProps) => {\n return (\n <CivicAuthConfigProvider\n oauthServer={props?.config?.oauthServer}\n clientId={props?.clientId}\n redirectUrl={props?.redirectUrl}\n nonce={props?.nonce}\n logoutRedirectUrl={props?.logoutRedirectUrl}\n displayMode={props?.displayMode}\n >\n <IframeProvider iframeMode={props.iframeMode}>\n <ClientTokenExchangeSessionProvider>\n <WrapperSessionAuthProvider {...props}>\n {children}\n </WrapperSessionAuthProvider>\n </ClientTokenExchangeSessionProvider>\n </IframeProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicAuthProvider, type CivicAuthProviderProps };\n"]}
1
+ {"version":3,"file":"CivicAuthProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,kCAAkC,EAAE,MAAM,2DAA2D,CAAC;AAC/G,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAI7E,MAAM,mBAAmB,GAAG,CAAC,EAAE,QAAQ,EAAiC,EAAE,EAAE;IAC1E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAAC;IAC/D,OAAO,CACL,KAAC,YAAY,IACX,OAAO,EAAE,IAAI,mBAAmB,EAAE,EAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,YAEvB,QAAQ,GACI,CAChB,CAAC;AACJ,CAAC,CAAC;AACF,MAAM,0BAA0B,GAAG,CAAC,EAClC,QAAQ,EACR,GAAG,KAAK,EACe,EAAE,EAAE;IAC3B,MAAM,WAAW,GAAG,6BAA6B,EAAE,CAAC;IACpD,OAAO,CACL,KAAC,eAAe,OAAK,WAAW,YAC9B,KAAC,YAAY,OACP,KAAK,EACT,YAAY,EAAE,IAAI,+BAA+B,EAAE,YAEnD,KAAC,aAAa,cACZ,KAAC,mBAAmB,cAAE,QAAQ,GAAuB,GACvC,GACH,GACC,CACnB,CAAC;AACJ,CAAC,CAAC;AACF,MAAM,iBAAiB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAA0B,EAAE,EAAE;IAC3E,OAAO,CACL,KAAC,uBAAuB,IACtB,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EACvC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EACzB,WAAW,EAAE,KAAK,EAAE,WAAW,EAC/B,KAAK,EAAE,KAAK,EAAE,KAAK,EACnB,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAC3C,WAAW,EAAE,KAAK,EAAE,WAAW,YAE/B,KAAC,kBAAkB,cACjB,KAAC,cAAc,IAAC,UAAU,EAAE,KAAK,CAAC,UAAU,YAC1C,KAAC,kCAAkC,cACjC,KAAC,0BAA0B,OAAK,KAAK,YAClC,QAAQ,GACkB,GACM,GACtB,GACE,GACG,CAC3B,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAA+B,CAAC","sourcesContent":["\"use client\";\nimport React from \"react\";\nimport { AuthProvider } from \"@/reactjs/providers/AuthProvider.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { UserProvider } from \"@/shared/providers/UserProvider.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { CivicAuthConfigProvider } from \"@/shared/providers/CivicAuthConfigContext.js\";\nimport { IframeProvider } from \"@/shared/providers/IframeProvider.js\";\nimport { ClientTokenExchangeSessionProvider } from \"@/reactjs/providers/ClientTokenExchangeSessionProvider.js\";\nimport { SessionProvider } from \"@/shared/providers/SessionProvider.js\";\nimport { useClientTokenExchangeSession } from \"@/reactjs/hooks/useClientTokenExchangeSession.js\";\nimport { TokenProvider } from \"@/shared/providers/TokenProvider.js\";\nimport { useAuth } from \"@/shared/hooks/useAuth.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { AuthStatusProvider } from \"@/shared/providers/AuthStatusContext.js\";\n\ntype CivicAuthProviderProps = Omit<AuthProviderProps, \"pkceConsumer\">;\n\nconst WrapperUserProvider = ({ children }: { children: React.ReactNode }) => {\n const { signIn, signOut, displayMode, authStatus } = useAuth();\n return (\n <UserProvider\n storage={new LocalStorageAdapter()}\n signIn={signIn}\n signOut={signOut}\n user={null}\n authStatus={authStatus}\n displayMode={displayMode}\n >\n {children}\n </UserProvider>\n );\n};\nconst WrapperSessionAuthProvider = ({\n children,\n ...props\n}: CivicAuthProviderProps) => {\n const sessionData = useClientTokenExchangeSession();\n return (\n <SessionProvider {...sessionData}>\n <AuthProvider\n {...props}\n pkceConsumer={new BrowserPublicClientPKCEProducer()}\n >\n <TokenProvider>\n <WrapperUserProvider>{children}</WrapperUserProvider>\n </TokenProvider>\n </AuthProvider>\n </SessionProvider>\n );\n};\nconst CivicAuthProvider = ({ children, ...props }: CivicAuthProviderProps) => {\n return (\n <CivicAuthConfigProvider\n oauthServer={props?.config?.oauthServer}\n clientId={props?.clientId}\n redirectUrl={props?.redirectUrl}\n nonce={props?.nonce}\n logoutRedirectUrl={props?.logoutRedirectUrl}\n displayMode={props?.displayMode}\n >\n <AuthStatusProvider>\n <IframeProvider iframeMode={props.iframeMode}>\n <ClientTokenExchangeSessionProvider>\n <WrapperSessionAuthProvider {...props}>\n {children}\n </WrapperSessionAuthProvider>\n </ClientTokenExchangeSessionProvider>\n </IframeProvider>\n </AuthStatusProvider>\n </CivicAuthConfigProvider>\n );\n};\n\nexport { CivicAuthProvider, type CivicAuthProviderProps };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ClientTokenExchangeSessionProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAU1D,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D,CAAC;AAcF,QAAA,MAAM,iCAAiC,yDACkC,CAAC;AAE1E,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,kCAAkC,GAAI,eAEzC,qCAAqC,qDA2LvC,CAAC;AAEF,YAAY,EAAE,qCAAqC,IAAI,kBAAkB,EAAE,CAAC;AAC5E,OAAO,EACL,kCAAkC,EAClC,iCAAiC,GAClC,CAAC"}
1
+ {"version":3,"file":"ClientTokenExchangeSessionProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAU1D,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D,CAAC;AAcF,QAAA,MAAM,iCAAiC,yDACkC,CAAC;AAE1E,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,kCAAkC,GAAI,eAEzC,qCAAqC,qDAsLvC,CAAC;AAEF,YAAY,EAAE,qCAAqC,IAAI,kBAAkB,EAAE,CAAC;AAC5E,OAAO,EACL,kCAAkC,EAClC,iCAAiC,GAClC,CAAC"}
@@ -123,10 +123,6 @@ const ClientTokenExchangeSessionProvider = ({ children, }) => {
123
123
  setValidationInProgress(true);
124
124
  try {
125
125
  const existingSessionData = await authService.validateExistingSession();
126
- // Check if component was unmounted during validation
127
- if (abortController.signal.aborted) {
128
- return;
129
- }
130
126
  if (existingSessionData.authenticated) {
131
127
  setSession(existingSessionData);
132
128
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"ClientTokenExchangeSessionProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport type { ReactNode } from \"react\";\nimport React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useState,\n useRef,\n} from \"react\";\nimport { BrowserAuthenticationService } from \"@/services/AuthenticationService.js\";\nimport type { AuthenticationResolver } from \"@/services/types.js\";\nimport { isWindowInIframe } from \"@/lib/windowUtil.js\";\nimport { AuthStatus, type SessionData } from \"@/types.js\";\nimport {\n useCurrentUrl,\n useCivicAuthConfig,\n useSignIn,\n useIframe,\n} from \"@/shared/hooks/index.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\n\nexport type ClientTokenExchangeSessionProviderOutput = {\n data: SessionData | null;\n error: Error | null;\n isLoading: boolean;\n doTokenExchange: null | ((url: string) => Promise<void>);\n};\nconst defaultSession: ClientTokenExchangeSessionProviderOutput = {\n data: {\n authenticated: false,\n idToken: undefined,\n accessToken: undefined,\n displayMode: \"iframe\",\n },\n error: null,\n isLoading: false,\n doTokenExchange: null,\n};\n\n// Context for exposing session specifically to the TokenProvider\nconst ClientTokenExchangeSessionContext =\n createContext<ClientTokenExchangeSessionProviderOutput>(defaultSession);\n\ntype ClientTokenExchangeSessionContextType = {\n children: ReactNode;\n};\n\nconst ClientTokenExchangeSessionProvider = ({\n children,\n}: ClientTokenExchangeSessionContextType) => {\n const authConfig = useCivicAuthConfig();\n const [authService, setAuthService] = useState<AuthenticationResolver>();\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [session, setSession] = useState<SessionData | null>(null);\n const { iframeRef } = useIframe();\n const currentUrl = useCurrentUrl();\n // Use the signIn hook with iframe displayMode\n const { startSignIn, authStatus } = useSignIn({\n displayMode: authConfig?.displayMode || \"iframe\",\n });\n\n // Add a ref to track processed codes\n const processedCodes = useRef(new Set<string>());\n\n useEffect(() => {\n if (!currentUrl || !authConfig) return;\n\n const {\n redirectUrl,\n clientId,\n oauthServer,\n scopes,\n logoutRedirectUrl,\n logoutUrl,\n } = authConfig;\n BrowserAuthenticationService.build({\n clientId,\n redirectUrl,\n logoutRedirectUrl,\n logoutUrl,\n oauthServer,\n scopes,\n displayMode: \"iframe\",\n }).then(setAuthService);\n }, [currentUrl, authConfig]);\n\n const isInIframe = isWindowInIframe(globalThis.window);\n\n const doTokenExchange = useCallback(\n async (inUrl: string) => {\n if (!authService) return;\n const url = new URL(inUrl);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n\n // Create a unique key for this code/state combination\n const exchangeKey = `${code}:${state}`;\n\n // If we've already processed this code, skip it\n if (processedCodes.current.has(exchangeKey)) {\n console.log(\"Token exchange already processed for this code\");\n return;\n }\n\n if (code && state) {\n try {\n // Mark this code as processed before starting the exchange\n processedCodes.current.add(exchangeKey);\n setIsLoading(true);\n await authService.tokenExchange(code, state);\n } catch (error) {\n setError(error as Error);\n setSession({ authenticated: false });\n }\n setIsLoading(false);\n }\n },\n [authService],\n );\n\n const onSignIn = useCallback(async () => {\n if (!authService) return;\n const session = await authService.getSessionData();\n setSession(session);\n }, [authService]);\n\n const onSignOut = useCallback(() => {\n setSession(null);\n }, []);\n\n useEffect(() => {\n LocalStorageAdapter.emitter.on(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.on(\"signOut\", onSignOut);\n return () => {\n LocalStorageAdapter.emitter.off(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.off(\"signOut\", onSignOut);\n };\n }, [onSignIn, onSignOut]);\n\n useEffect(() => {\n if (!authConfig) {\n setIsLoading(true);\n } else {\n setIsLoading(false);\n }\n }, [authConfig]);\n\n const [validationInProgress, setValidationInProgress] = useState(false);\n // Handle page load or refocus\n useEffect(() => {\n if (\n !authConfig?.redirectUrl ||\n !authService ||\n !currentUrl ||\n isInIframe ||\n isLoading\n ) {\n return;\n }\n\n // We specifically don't want to abort token refresh operations\n // The AbortController is mainly used to prevent token exchange after unmount\n const abortController = new AbortController();\n\n const onPageLoad = async () => {\n if (validationInProgress || authStatus === AuthStatus.SIGNING_OUT) return;\n\n // if we have existing tokens, then validate them and return the session data\n // otherwise check if we have a code in the url and exchange it for tokens\n // if we have neither, initiate sign-in flow\n setValidationInProgress(true);\n\n try {\n const existingSessionData = await authService.validateExistingSession();\n\n // Check if component was unmounted during validation\n if (abortController.signal.aborted) {\n return;\n }\n\n if (existingSessionData.authenticated) {\n setSession(existingSessionData);\n return;\n }\n // If we have a code in the URL, attempt token exchange\n if (new URL(currentUrl).searchParams.get(\"code\")) {\n await doTokenExchange(currentUrl);\n return;\n }\n // No valid session and no code in URL - initiate sign-in\n // But only if we're not in an iframe (to prevent infinite loops in embedded scenarios)\n if (!isInIframe && authConfig) {\n const ref = getIframeRef(iframeRef?.current, true);\n if (ref && authConfig?.displayMode === \"iframe\") {\n startSignIn();\n }\n }\n } catch (error) {\n console.error(\"Error during session validation:\", error);\n } finally {\n setValidationInProgress(false);\n }\n };\n\n onPageLoad();\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n authConfig,\n authService,\n currentUrl,\n doTokenExchange,\n isInIframe,\n isLoading,\n startSignIn,\n ]);\n\n const value = useMemo(\n () => ({\n data: session,\n error,\n isLoading,\n doTokenExchange: authService ? doTokenExchange : null,\n }),\n [session, error, isLoading, authService, doTokenExchange],\n );\n\n return (\n <ClientTokenExchangeSessionContext.Provider value={value}>\n {children}\n </ClientTokenExchangeSessionContext.Provider>\n );\n};\n\nexport type { ClientTokenExchangeSessionContextType as SessionContextType };\nexport {\n ClientTokenExchangeSessionProvider,\n ClientTokenExchangeSessionContext,\n};\n"]}
1
+ {"version":3,"file":"ClientTokenExchangeSessionProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport type { ReactNode } from \"react\";\nimport React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useState,\n useRef,\n} from \"react\";\nimport { BrowserAuthenticationService } from \"@/services/AuthenticationService.js\";\nimport type { AuthenticationResolver } from \"@/services/types.js\";\nimport { isWindowInIframe } from \"@/lib/windowUtil.js\";\nimport { AuthStatus, type SessionData } from \"@/types.js\";\nimport {\n useCurrentUrl,\n useCivicAuthConfig,\n useSignIn,\n useIframe,\n} from \"@/shared/hooks/index.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\n\nexport type ClientTokenExchangeSessionProviderOutput = {\n data: SessionData | null;\n error: Error | null;\n isLoading: boolean;\n doTokenExchange: null | ((url: string) => Promise<void>);\n};\nconst defaultSession: ClientTokenExchangeSessionProviderOutput = {\n data: {\n authenticated: false,\n idToken: undefined,\n accessToken: undefined,\n displayMode: \"iframe\",\n },\n error: null,\n isLoading: false,\n doTokenExchange: null,\n};\n\n// Context for exposing session specifically to the TokenProvider\nconst ClientTokenExchangeSessionContext =\n createContext<ClientTokenExchangeSessionProviderOutput>(defaultSession);\n\ntype ClientTokenExchangeSessionContextType = {\n children: ReactNode;\n};\n\nconst ClientTokenExchangeSessionProvider = ({\n children,\n}: ClientTokenExchangeSessionContextType) => {\n const authConfig = useCivicAuthConfig();\n const [authService, setAuthService] = useState<AuthenticationResolver>();\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [session, setSession] = useState<SessionData | null>(null);\n const { iframeRef } = useIframe();\n const currentUrl = useCurrentUrl();\n // Use the signIn hook with iframe displayMode\n const { startSignIn, authStatus } = useSignIn({\n displayMode: authConfig?.displayMode || \"iframe\",\n });\n\n // Add a ref to track processed codes\n const processedCodes = useRef(new Set<string>());\n\n useEffect(() => {\n if (!currentUrl || !authConfig) return;\n\n const {\n redirectUrl,\n clientId,\n oauthServer,\n scopes,\n logoutRedirectUrl,\n logoutUrl,\n } = authConfig;\n BrowserAuthenticationService.build({\n clientId,\n redirectUrl,\n logoutRedirectUrl,\n logoutUrl,\n oauthServer,\n scopes,\n displayMode: \"iframe\",\n }).then(setAuthService);\n }, [currentUrl, authConfig]);\n\n const isInIframe = isWindowInIframe(globalThis.window);\n\n const doTokenExchange = useCallback(\n async (inUrl: string) => {\n if (!authService) return;\n const url = new URL(inUrl);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n\n // Create a unique key for this code/state combination\n const exchangeKey = `${code}:${state}`;\n\n // If we've already processed this code, skip it\n if (processedCodes.current.has(exchangeKey)) {\n console.log(\"Token exchange already processed for this code\");\n return;\n }\n\n if (code && state) {\n try {\n // Mark this code as processed before starting the exchange\n processedCodes.current.add(exchangeKey);\n setIsLoading(true);\n await authService.tokenExchange(code, state);\n } catch (error) {\n setError(error as Error);\n setSession({ authenticated: false });\n }\n setIsLoading(false);\n }\n },\n [authService],\n );\n\n const onSignIn = useCallback(async () => {\n if (!authService) return;\n const session = await authService.getSessionData();\n setSession(session);\n }, [authService]);\n\n const onSignOut = useCallback(() => {\n setSession(null);\n }, []);\n\n useEffect(() => {\n LocalStorageAdapter.emitter.on(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.on(\"signOut\", onSignOut);\n return () => {\n LocalStorageAdapter.emitter.off(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.off(\"signOut\", onSignOut);\n };\n }, [onSignIn, onSignOut]);\n\n useEffect(() => {\n if (!authConfig) {\n setIsLoading(true);\n } else {\n setIsLoading(false);\n }\n }, [authConfig]);\n\n const [validationInProgress, setValidationInProgress] = useState(false);\n // Handle page load or refocus\n useEffect(() => {\n if (\n !authConfig?.redirectUrl ||\n !authService ||\n !currentUrl ||\n isInIframe ||\n isLoading\n ) {\n return;\n }\n\n // We specifically don't want to abort token refresh operations\n // The AbortController is mainly used to prevent token exchange after unmount\n const abortController = new AbortController();\n\n const onPageLoad = async () => {\n if (validationInProgress || authStatus === AuthStatus.SIGNING_OUT) return;\n\n // if we have existing tokens, then validate them and return the session data\n // otherwise check if we have a code in the url and exchange it for tokens\n // if we have neither, initiate sign-in flow\n setValidationInProgress(true);\n\n try {\n const existingSessionData = await authService.validateExistingSession();\n\n if (existingSessionData.authenticated) {\n setSession(existingSessionData);\n return;\n }\n // If we have a code in the URL, attempt token exchange\n if (new URL(currentUrl).searchParams.get(\"code\")) {\n await doTokenExchange(currentUrl);\n return;\n }\n // No valid session and no code in URL - initiate sign-in\n // But only if we're not in an iframe (to prevent infinite loops in embedded scenarios)\n if (!isInIframe && authConfig) {\n const ref = getIframeRef(iframeRef?.current, true);\n if (ref && authConfig?.displayMode === \"iframe\") {\n startSignIn();\n }\n }\n } catch (error) {\n console.error(\"Error during session validation:\", error);\n } finally {\n setValidationInProgress(false);\n }\n };\n\n onPageLoad();\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n authConfig,\n authService,\n currentUrl,\n doTokenExchange,\n isInIframe,\n isLoading,\n startSignIn,\n ]);\n\n const value = useMemo(\n () => ({\n data: session,\n error,\n isLoading,\n doTokenExchange: authService ? doTokenExchange : null,\n }),\n [session, error, isLoading, authService, doTokenExchange],\n );\n\n return (\n <ClientTokenExchangeSessionContext.Provider value={value}>\n {children}\n </ClientTokenExchangeSessionContext.Provider>\n );\n};\n\nexport type { ClientTokenExchangeSessionContextType as SessionContextType };\nexport {\n ClientTokenExchangeSessionProvider,\n ClientTokenExchangeSessionContext,\n};\n"]}
@@ -9,4 +9,5 @@ export { useClientTokenExchangeSession } from "../../reactjs/hooks/useClientToke
9
9
  export { useWindowFocused } from "../../shared/hooks/useWindowFocused.js";
10
10
  export { useRefresh } from "../../shared/hooks/useRefresh.js";
11
11
  export { useSignIn } from "../../shared/hooks/useSignIn.js";
12
+ export { useAuthStatus } from "../../shared/providers/AuthStatusContext.js";
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC"}
@@ -9,4 +9,5 @@ export { useClientTokenExchangeSession } from "../../reactjs/hooks/useClientToke
9
9
  export { useWindowFocused } from "../../shared/hooks/useWindowFocused.js";
10
10
  export { useRefresh } from "../../shared/hooks/useRefresh.js";
11
11
  export { useSignIn } from "../../shared/hooks/useSignIn.js";
12
+ export { useAuthStatus } from "../../shared/providers/AuthStatusContext.js";
12
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { useToken } from \"@/shared/hooks/useToken.js\";\nexport { useAuth } from \"@/shared/hooks/useAuth.js\";\nexport { useIframe } from \"@/shared/hooks/useIframe.js\";\nexport { useSession } from \"@/shared/hooks/useSession.js\";\nexport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nexport { useOAuthEndpoints } from \"@/shared/hooks/useOAuthEndpoints.js\";\nexport { useCurrentUrl } from \"@/shared/hooks/useCurrentUrl.js\";\nexport { useClientTokenExchangeSession } from \"@/reactjs/hooks/useClientTokenExchangeSession.js\";\nexport { useWindowFocused } from \"@/shared/hooks/useWindowFocused.js\";\nexport { useRefresh } from \"@/shared/hooks/useRefresh.js\";\nexport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC","sourcesContent":["export { useToken } from \"@/shared/hooks/useToken.js\";\nexport { useAuth } from \"@/shared/hooks/useAuth.js\";\nexport { useIframe } from \"@/shared/hooks/useIframe.js\";\nexport { useSession } from \"@/shared/hooks/useSession.js\";\nexport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nexport { useOAuthEndpoints } from \"@/shared/hooks/useOAuthEndpoints.js\";\nexport { useCurrentUrl } from \"@/shared/hooks/useCurrentUrl.js\";\nexport { useClientTokenExchangeSession } from \"@/reactjs/hooks/useClientTokenExchangeSession.js\";\nexport { useWindowFocused } from \"@/shared/hooks/useWindowFocused.js\";\nexport { useRefresh } from \"@/shared/hooks/useRefresh.js\";\nexport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nexport { useAuthStatus } from \"@/shared/providers/AuthStatusContext.js\";\n"]}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * React hook to detect if the current window is running inside an iframe
3
+ * @returns boolean indicating whether the current window is in an iframe
4
+ */
1
5
  declare const useIsInIframe: () => boolean;
2
6
  export { useIsInIframe };
3
7
  //# sourceMappingURL=useIsInIframe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useIsInIframe.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useIsInIframe.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,aAAa,eASlB,CAAC;AACF,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"useIsInIframe.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useIsInIframe.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,QAAA,MAAM,aAAa,eAelB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -1,14 +1,23 @@
1
1
  import { isWindowInIframe } from "../../lib/windowUtil.js";
2
2
  import { useEffect, useState } from "react";
3
+ /**
4
+ * React hook to detect if the current window is running inside an iframe
5
+ * @returns boolean indicating whether the current window is in an iframe
6
+ */
3
7
  const useIsInIframe = () => {
4
- const [isInIframe, setIsInIframe] = useState(true);
8
+ // Start with undefined to indicate we don't know yet
9
+ const [isInIframe, setIsInIframe] = useState(undefined);
5
10
  useEffect(() => {
6
11
  if (typeof globalThis.window !== "undefined") {
7
12
  const isInIframeVal = isWindowInIframe(globalThis.window);
8
13
  setIsInIframe(isInIframeVal);
9
14
  }
15
+ else {
16
+ setIsInIframe(false);
17
+ }
10
18
  }, []);
11
- return isInIframe;
19
+ // Return false if undefined to be safe
20
+ return isInIframe === undefined ? false : isInIframe;
12
21
  };
13
22
  export { useIsInIframe };
14
23
  //# sourceMappingURL=useIsInIframe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useIsInIframe.js","sourceRoot":"","sources":["../../../src/shared/hooks/useIsInIframe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,aAAa,GAAG,GAAG,EAAE;IACzB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC7C,MAAM,aAAa,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC1D,aAAa,CAAC,aAAa,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AACF,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { isWindowInIframe } from \"@/lib/windowUtil.js\";\nimport { useEffect, useState } from \"react\";\n\nconst useIsInIframe = () => {\n const [isInIframe, setIsInIframe] = useState(true);\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const isInIframeVal = isWindowInIframe(globalThis.window);\n setIsInIframe(isInIframeVal);\n }\n }, []);\n return isInIframe;\n};\nexport { useIsInIframe };\n"]}
1
+ {"version":3,"file":"useIsInIframe.js","sourceRoot":"","sources":["../../../src/shared/hooks/useIsInIframe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C;;;GAGG;AACH,MAAM,aAAa,GAAG,GAAG,EAAE;IACzB,qDAAqD;IACrD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAsB,SAAS,CAAC,CAAC;IAE7E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC7C,MAAM,aAAa,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC1D,aAAa,CAAC,aAAa,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,uCAAuC;IACvC,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;AACvD,CAAC,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { isWindowInIframe } from \"@/lib/windowUtil.js\";\nimport { useEffect, useState } from \"react\";\n\n/**\n * React hook to detect if the current window is running inside an iframe\n * @returns boolean indicating whether the current window is in an iframe\n */\nconst useIsInIframe = () => {\n // Start with undefined to indicate we don't know yet\n const [isInIframe, setIsInIframe] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const isInIframeVal = isWindowInIframe(globalThis.window);\n setIsInIframe(isInIframeVal);\n } else {\n setIsInIframe(false);\n }\n }, []);\n\n // Return false if undefined to be safe\n return isInIframe === undefined ? false : isInIframe;\n};\n\nexport { useIsInIframe };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useSignIn.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,UAAU,EACV,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOpE,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AACF,QAAA,MAAM,SAAS,GACb,yDAAwD,WAEvD;kBAwGoC,OAAO,CAAC,IAAI,CAAC;;;;;CAsFnD,CAAC;AACF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"useSignIn.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,UAAU,EACV,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQpE,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAGF,QAAA,MAAM,SAAS,GACb,yDAAwD,WAEvD;kBA2IoC,OAAO,CAAC,IAAI,CAAC;;;;;CAsHnD,CAAC;AACF,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -3,21 +3,26 @@ import { BrowserPublicClientPKCEProducer } from "../../services/PKCE.js";
3
3
  import { useCivicAuthConfig } from "../../shared/hooks/useCivicAuthConfig.js";
4
4
  import { AuthStatus, } from "../../types.js";
5
5
  import { useIframe } from "../../shared/hooks/useIframe.js";
6
- import { useCallback, useEffect, useMemo, useState } from "react";
6
+ import { useCallback, useEffect, useMemo, useRef } from "react";
7
7
  import { PopupError } from "../../services/types.js";
8
8
  import { useSession } from "./useSession.js";
9
9
  import { LocalStorageAdapter } from "../../browser/storage.js";
10
10
  import { clearTokens, clearUser } from "../lib/util.js";
11
11
  import { useLocalStorage } from "usehooks-ts";
12
12
  import { LOGOUT_STATE } from "../../constants.js";
13
+ import { useAuthStatus } from "../../shared/providers/AuthStatusContext.js";
14
+ const SIGN_IN_TIMEOUT_MS = 9 * 60 * 1000; // 9 minutes in milliseconds
13
15
  const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
14
16
  displayMode: "iframe",
15
17
  }) => {
16
18
  const civicAuthConfig = useCivicAuthConfig();
17
19
  const { iframeRef, logoutIframeRef, setIframeIsVisible, iframeIsVisible, setLogoutIframeIsVisible, iframeAborted, setIframeAborted, } = useIframe();
18
20
  const { data: session } = useSession();
19
- const [authStatus, setAuthStatus] = useState(AuthStatus.UNAUTHENTICATED);
21
+ // Use the shared auth status from context instead of local state
22
+ const { authStatus, setAuthStatus } = useAuthStatus();
20
23
  const [, setDesignOption] = useLocalStorage(`loginAppDesign`, { colorMode: "auto" });
24
+ const timeoutRef = useRef(null);
25
+ const authStatusRef = useRef(AuthStatus.UNAUTHENTICATED);
21
26
  const authInitiator = useMemo(() => {
22
27
  if (!civicAuthConfig) {
23
28
  return null;
@@ -38,9 +43,15 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
38
43
  }, [civicAuthConfig, displayMode, pkceConsumer, setDesignOption]);
39
44
  useEffect(() => {
40
45
  return () => {
46
+ // Clean up on unmount
41
47
  if (authInitiator) {
42
48
  authInitiator.cleanup();
43
49
  }
50
+ // Clear any existing timeout
51
+ if (timeoutRef.current !== null) {
52
+ window.clearTimeout(timeoutRef.current);
53
+ timeoutRef.current = null;
54
+ }
44
55
  };
45
56
  }, [authInitiator]);
46
57
  // This effect is used to clear the tokens and user when the user signs out after a redirect
@@ -67,8 +78,23 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
67
78
  if (authStatus === AuthStatus.AUTHENTICATING) {
68
79
  return;
69
80
  }
81
+ // Clear any existing timeout
82
+ if (timeoutRef.current !== null) {
83
+ window.clearTimeout(timeoutRef.current);
84
+ timeoutRef.current = null;
85
+ }
70
86
  setAuthStatus(AuthStatus.AUTHENTICATING);
71
87
  authInitiator.setDisplayMode(displayMode);
88
+ // Set a timeout to reset authentication state and retry if still authenticating
89
+ timeoutRef.current = window.setTimeout(() => {
90
+ // Check the current auth status via ref when the timeout fires
91
+ if (authStatusRef.current === AuthStatus.AUTHENTICATING) {
92
+ console.log("Sign-in timeout reached. Resetting authentication state.");
93
+ setAuthStatus(AuthStatus.UNAUTHENTICATED);
94
+ // Call startSignIn again to restart with fresh state
95
+ startSignIn();
96
+ }
97
+ }, SIGN_IN_TIMEOUT_MS);
72
98
  const useIframeRef = iframeRef?.current || null;
73
99
  await authInitiator.signIn(useIframeRef).catch((error) => {
74
100
  setAuthStatus(AuthStatus.ERROR);
@@ -84,7 +110,14 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
84
110
  authInitiator.signIn(useIframeRef); // retry the sign in
85
111
  }
86
112
  });
87
- }, [authInitiator, displayMode, iframeRef, setIframeIsVisible, authStatus]);
113
+ }, [
114
+ authInitiator,
115
+ displayMode,
116
+ iframeRef,
117
+ setIframeIsVisible,
118
+ authStatus,
119
+ setAuthStatus,
120
+ ]);
88
121
  const signIn = useCallback(async () => {
89
122
  if (displayMode === "iframe") {
90
123
  setIframeIsVisible(true);
@@ -129,18 +162,44 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
129
162
  setIframeIsVisible,
130
163
  preSignOut,
131
164
  logoutIframeRef,
165
+ setAuthStatus,
132
166
  ]);
167
+ // Keep the authStatusRef in sync with authStatus
168
+ useEffect(() => {
169
+ authStatusRef.current = authStatus;
170
+ if (authStatus !== AuthStatus.AUTHENTICATING &&
171
+ timeoutRef.current !== null) {
172
+ window.clearTimeout(timeoutRef.current);
173
+ timeoutRef.current = null;
174
+ }
175
+ }, [authStatus]);
133
176
  useEffect(() => {
134
177
  if (session?.authenticated) {
135
178
  setAuthStatus(AuthStatus.AUTHENTICATED);
179
+ // Clear timeout when authentication is successful
180
+ if (timeoutRef.current !== null) {
181
+ window.clearTimeout(timeoutRef.current);
182
+ timeoutRef.current = null;
183
+ }
136
184
  }
137
185
  if (displayMode === "iframe" && iframeAborted) {
138
186
  setIframeAborted(false);
187
+ // Clear timeout when iframe is aborted
188
+ if (timeoutRef.current !== null) {
189
+ window.clearTimeout(timeoutRef.current);
190
+ timeoutRef.current = null;
191
+ }
139
192
  }
140
193
  if (!session?.authenticated) {
141
194
  setAuthStatus(AuthStatus.UNAUTHENTICATED);
142
195
  }
143
- }, [displayMode, iframeAborted, session?.authenticated, setIframeAborted]);
196
+ }, [
197
+ displayMode,
198
+ iframeAborted,
199
+ session?.authenticated,
200
+ setIframeAborted,
201
+ setAuthStatus,
202
+ ]);
144
203
  // handle logout finished
145
204
  useEffect(() => {
146
205
  if (authStatus === AuthStatus.SIGNING_OUT && !session?.authenticated) {
@@ -157,6 +216,7 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
157
216
  displayMode,
158
217
  iframeIsVisible,
159
218
  authStatus,
219
+ setAuthStatus,
160
220
  ]);
161
221
  return {
162
222
  signIn,
@@ -1 +1 @@
1
- {"version":3,"file":"useSignIn.js","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport {\n AuthStatus,\n type DisplayMode,\n type LoginAppDesignOptions,\n} from \"@/types.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { PopupError, type PKCEConsumer } from \"@/services/types.js\";\nimport { useSession } from \"./useSession.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { clearTokens, clearUser } from \"../lib/util.js\";\nimport { useLocalStorage } from \"usehooks-ts\";\nimport { LOGOUT_STATE } from \"@/constants.js\";\n\ntype SignInProps = {\n pkceConsumer?: PKCEConsumer;\n preSignOut?: () => Promise<void>;\n postSignOut?: () => Promise<void>;\n displayMode: DisplayMode;\n};\nconst useSignIn = (\n { pkceConsumer, preSignOut, postSignOut, displayMode }: SignInProps = {\n displayMode: \"iframe\",\n },\n) => {\n const civicAuthConfig = useCivicAuthConfig();\n const {\n iframeRef,\n logoutIframeRef,\n setIframeIsVisible,\n iframeIsVisible,\n setLogoutIframeIsVisible,\n iframeAborted,\n setIframeAborted,\n } = useIframe();\n const { data: session } = useSession();\n const [authStatus, setAuthStatus] = useState(AuthStatus.UNAUTHENTICATED);\n const [, setDesignOption] = useLocalStorage<LoginAppDesignOptions>(\n `loginAppDesign`,\n { colorMode: \"auto\" },\n );\n\n const authInitiator = useMemo(() => {\n if (!civicAuthConfig) {\n return null;\n }\n const {\n clientId,\n redirectUrl,\n logoutUrl,\n logoutRedirectUrl,\n nonce,\n oauthServer,\n endpoints,\n scopes,\n } = civicAuthConfig;\n return new BrowserAuthenticationInitiator(\n {\n pkceConsumer: pkceConsumer || new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n clientId,\n redirectUrl,\n logoutUrl,\n logoutRedirectUrl,\n scopes,\n displayMode,\n oauthServer,\n endpointOverrides: endpoints,\n nonce,\n },\n setDesignOption,\n );\n }, [civicAuthConfig, displayMode, pkceConsumer, setDesignOption]);\n\n useEffect(() => {\n return () => {\n if (authInitiator) {\n authInitiator.cleanup();\n }\n };\n }, [authInitiator]);\n\n // This effect is used to clear the tokens and user when the user signs out after a redirect\n useEffect(() => {\n const params = new URLSearchParams(window.location.search);\n const state = params.get(\"state\");\n const localStorage = new LocalStorageAdapter();\n localStorage.get(LOGOUT_STATE).then((storedLogoutState) => {\n if (state && state === storedLogoutState) {\n // Clear storage\n clearTokens(localStorage);\n clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n\n // Clean up storage and URL\n sessionStorage.removeItem(LOGOUT_STATE);\n const cleanUrl = window.location.href.split(\"?\")[0];\n window.history.replaceState({}, document.title, cleanUrl);\n }\n });\n }, []);\n\n const startSignIn = useCallback(async () => {\n if (!authInitiator) return;\n\n if (authStatus === AuthStatus.AUTHENTICATING) {\n return;\n }\n setAuthStatus(AuthStatus.AUTHENTICATING);\n authInitiator.setDisplayMode(displayMode);\n\n const useIframeRef = iframeRef?.current || null;\n await authInitiator.signIn(useIframeRef).catch((error) => {\n setAuthStatus(AuthStatus.ERROR);\n console.error(\"signIn error\", {\n error,\n isPopupError: error instanceof PopupError,\n });\n // if we've tried to open a popup and it has failed, then fallback to redirect mode\n if (error instanceof PopupError) {\n setIframeIsVisible(false); // hide the iframe\n authInitiator.cleanup(); // clear any event listeners from before\n authInitiator.setDisplayMode(\"redirect\"); // switch to redirect mode\n authInitiator.signIn(useIframeRef); // retry the sign in\n }\n });\n }, [authInitiator, displayMode, iframeRef, setIframeIsVisible, authStatus]);\n\n const signIn = useCallback(async (): Promise<void> => {\n if (displayMode === \"iframe\") {\n setIframeIsVisible(true);\n }\n return startSignIn();\n }, [startSignIn, displayMode, setIframeIsVisible]);\n\n const signOut = useCallback(async () => {\n const idToken = session?.idToken;\n if (!authInitiator) return;\n\n setAuthStatus(AuthStatus.SIGNING_OUT);\n if (displayMode === \"iframe\") {\n setIframeIsVisible(false);\n setLogoutIframeIsVisible(true);\n }\n\n try {\n await preSignOut?.();\n\n const useIframeRef = logoutIframeRef?.current || null;\n await authInitiator.signOut(idToken, useIframeRef).catch((error) => {\n setAuthStatus(AuthStatus.ERROR);\n console.error(\"signOut error\", {\n error,\n isPopupError: error instanceof PopupError,\n });\n\n // Same popup fallback as signIn\n if (error instanceof PopupError) {\n setLogoutIframeIsVisible(false);\n authInitiator.cleanup();\n authInitiator.setDisplayMode(\"redirect\");\n authInitiator.signOut(idToken, useIframeRef);\n }\n });\n } catch (error) {\n console.error(\"Signout error:\", error);\n }\n }, [\n session?.idToken,\n authInitiator,\n displayMode,\n setLogoutIframeIsVisible,\n setIframeIsVisible,\n preSignOut,\n logoutIframeRef,\n ]);\n\n useEffect(() => {\n if (session?.authenticated) {\n setAuthStatus(AuthStatus.AUTHENTICATED);\n }\n if (displayMode === \"iframe\" && iframeAborted) {\n setIframeAborted(false);\n }\n if (!session?.authenticated) {\n setAuthStatus(AuthStatus.UNAUTHENTICATED);\n }\n }, [displayMode, iframeAborted, session?.authenticated, setIframeAborted]);\n\n // handle logout finished\n useEffect(() => {\n if (authStatus === AuthStatus.SIGNING_OUT && !session?.authenticated) {\n setAuthStatus(AuthStatus.UNAUTHENTICATED);\n postSignOut?.().then(() => {\n setLogoutIframeIsVisible(false);\n });\n return;\n }\n }, [\n session,\n postSignOut,\n setLogoutIframeIsVisible,\n displayMode,\n iframeIsVisible,\n authStatus,\n ]);\n\n return {\n signIn,\n signOut,\n startSignIn,\n authStatus,\n displayMode,\n };\n};\nexport { useSignIn };\n"]}
1
+ {"version":3,"file":"useSignIn.js","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport {\n AuthStatus,\n type DisplayMode,\n type LoginAppDesignOptions,\n} from \"@/types.js\";\nimport { useIframe } from \"@/shared/hooks/useIframe.js\";\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { PopupError, type PKCEConsumer } from \"@/services/types.js\";\nimport { useSession } from \"./useSession.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { clearTokens, clearUser } from \"../lib/util.js\";\nimport { useLocalStorage } from \"usehooks-ts\";\nimport { LOGOUT_STATE } from \"@/constants.js\";\nimport { useAuthStatus } from \"@/shared/providers/AuthStatusContext.js\";\n\ntype SignInProps = {\n pkceConsumer?: PKCEConsumer;\n preSignOut?: () => Promise<void>;\n postSignOut?: () => Promise<void>;\n displayMode: DisplayMode;\n};\nconst SIGN_IN_TIMEOUT_MS = 9 * 60 * 1000; // 9 minutes in milliseconds\n\nconst useSignIn = (\n { pkceConsumer, preSignOut, postSignOut, displayMode }: SignInProps = {\n displayMode: \"iframe\",\n },\n) => {\n const civicAuthConfig = useCivicAuthConfig();\n const {\n iframeRef,\n logoutIframeRef,\n setIframeIsVisible,\n iframeIsVisible,\n setLogoutIframeIsVisible,\n iframeAborted,\n setIframeAborted,\n } = useIframe();\n const { data: session } = useSession();\n // Use the shared auth status from context instead of local state\n const { authStatus, setAuthStatus } = useAuthStatus();\n const [, setDesignOption] = useLocalStorage<LoginAppDesignOptions>(\n `loginAppDesign`,\n { colorMode: \"auto\" },\n );\n const timeoutRef = useRef<number | null>(null);\n const authStatusRef = useRef<AuthStatus>(AuthStatus.UNAUTHENTICATED);\n\n const authInitiator = useMemo(() => {\n if (!civicAuthConfig) {\n return null;\n }\n const {\n clientId,\n redirectUrl,\n logoutUrl,\n logoutRedirectUrl,\n nonce,\n oauthServer,\n endpoints,\n scopes,\n } = civicAuthConfig;\n return new BrowserAuthenticationInitiator(\n {\n pkceConsumer: pkceConsumer || new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n clientId,\n redirectUrl,\n logoutUrl,\n logoutRedirectUrl,\n scopes,\n displayMode,\n oauthServer,\n endpointOverrides: endpoints,\n nonce,\n },\n setDesignOption,\n );\n }, [civicAuthConfig, displayMode, pkceConsumer, setDesignOption]);\n\n useEffect(() => {\n return () => {\n // Clean up on unmount\n if (authInitiator) {\n authInitiator.cleanup();\n }\n\n // Clear any existing timeout\n if (timeoutRef.current !== null) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n };\n }, [authInitiator]);\n\n // This effect is used to clear the tokens and user when the user signs out after a redirect\n useEffect(() => {\n const params = new URLSearchParams(window.location.search);\n const state = params.get(\"state\");\n const localStorage = new LocalStorageAdapter();\n localStorage.get(LOGOUT_STATE).then((storedLogoutState) => {\n if (state && state === storedLogoutState) {\n // Clear storage\n clearTokens(localStorage);\n clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n\n // Clean up storage and URL\n sessionStorage.removeItem(LOGOUT_STATE);\n const cleanUrl = window.location.href.split(\"?\")[0];\n window.history.replaceState({}, document.title, cleanUrl);\n }\n });\n }, []);\n\n const startSignIn = useCallback(async () => {\n if (!authInitiator) return;\n\n if (authStatus === AuthStatus.AUTHENTICATING) {\n return;\n }\n\n // Clear any existing timeout\n if (timeoutRef.current !== null) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n\n setAuthStatus(AuthStatus.AUTHENTICATING);\n authInitiator.setDisplayMode(displayMode);\n\n // Set a timeout to reset authentication state and retry if still authenticating\n timeoutRef.current = window.setTimeout(() => {\n // Check the current auth status via ref when the timeout fires\n if (authStatusRef.current === AuthStatus.AUTHENTICATING) {\n console.log(\"Sign-in timeout reached. Resetting authentication state.\");\n setAuthStatus(AuthStatus.UNAUTHENTICATED);\n // Call startSignIn again to restart with fresh state\n startSignIn();\n }\n }, SIGN_IN_TIMEOUT_MS);\n\n const useIframeRef = iframeRef?.current || null;\n await authInitiator.signIn(useIframeRef).catch((error) => {\n setAuthStatus(AuthStatus.ERROR);\n console.error(\"signIn error\", {\n error,\n isPopupError: error instanceof PopupError,\n });\n // if we've tried to open a popup and it has failed, then fallback to redirect mode\n if (error instanceof PopupError) {\n setIframeIsVisible(false); // hide the iframe\n authInitiator.cleanup(); // clear any event listeners from before\n authInitiator.setDisplayMode(\"redirect\"); // switch to redirect mode\n authInitiator.signIn(useIframeRef); // retry the sign in\n }\n });\n }, [\n authInitiator,\n displayMode,\n iframeRef,\n setIframeIsVisible,\n authStatus,\n setAuthStatus,\n ]);\n\n const signIn = useCallback(async (): Promise<void> => {\n if (displayMode === \"iframe\") {\n setIframeIsVisible(true);\n }\n return startSignIn();\n }, [startSignIn, displayMode, setIframeIsVisible]);\n\n const signOut = useCallback(async () => {\n const idToken = session?.idToken;\n if (!authInitiator) return;\n\n setAuthStatus(AuthStatus.SIGNING_OUT);\n if (displayMode === \"iframe\") {\n setIframeIsVisible(false);\n setLogoutIframeIsVisible(true);\n }\n\n try {\n await preSignOut?.();\n\n const useIframeRef = logoutIframeRef?.current || null;\n await authInitiator.signOut(idToken, useIframeRef).catch((error) => {\n setAuthStatus(AuthStatus.ERROR);\n console.error(\"signOut error\", {\n error,\n isPopupError: error instanceof PopupError,\n });\n\n // Same popup fallback as signIn\n if (error instanceof PopupError) {\n setLogoutIframeIsVisible(false);\n authInitiator.cleanup();\n authInitiator.setDisplayMode(\"redirect\");\n authInitiator.signOut(idToken, useIframeRef);\n }\n });\n } catch (error) {\n console.error(\"Signout error:\", error);\n }\n }, [\n session?.idToken,\n authInitiator,\n displayMode,\n setLogoutIframeIsVisible,\n setIframeIsVisible,\n preSignOut,\n logoutIframeRef,\n setAuthStatus,\n ]);\n\n // Keep the authStatusRef in sync with authStatus\n useEffect(() => {\n authStatusRef.current = authStatus;\n if (\n authStatus !== AuthStatus.AUTHENTICATING &&\n timeoutRef.current !== null\n ) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }, [authStatus]);\n\n useEffect(() => {\n if (session?.authenticated) {\n setAuthStatus(AuthStatus.AUTHENTICATED);\n\n // Clear timeout when authentication is successful\n if (timeoutRef.current !== null) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }\n if (displayMode === \"iframe\" && iframeAborted) {\n setIframeAborted(false);\n\n // Clear timeout when iframe is aborted\n if (timeoutRef.current !== null) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }\n if (!session?.authenticated) {\n setAuthStatus(AuthStatus.UNAUTHENTICATED);\n }\n }, [\n displayMode,\n iframeAborted,\n session?.authenticated,\n setIframeAborted,\n setAuthStatus,\n ]);\n\n // handle logout finished\n useEffect(() => {\n if (authStatus === AuthStatus.SIGNING_OUT && !session?.authenticated) {\n setAuthStatus(AuthStatus.UNAUTHENTICATED);\n postSignOut?.().then(() => {\n setLogoutIframeIsVisible(false);\n });\n return;\n }\n }, [\n session,\n postSignOut,\n setLogoutIframeIsVisible,\n displayMode,\n iframeIsVisible,\n authStatus,\n setAuthStatus,\n ]);\n\n return {\n signIn,\n signOut,\n startSignIn,\n authStatus,\n displayMode,\n };\n};\nexport { useSignIn };\n"]}
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import { AuthStatus } from "../../types.js";
3
+ interface AuthStatusContextType {
4
+ authStatus: AuthStatus;
5
+ setAuthStatus: React.Dispatch<React.SetStateAction<AuthStatus>>;
6
+ }
7
+ export declare const AuthStatusProvider: React.FC<{
8
+ children: React.ReactNode;
9
+ }>;
10
+ export declare const useAuthStatus: () => AuthStatusContextType;
11
+ export {};
12
+ //# sourceMappingURL=AuthStatusContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthStatusContext.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/AuthStatusContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8C,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,UAAU,qBAAqB;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;CACjE;AAMD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAYtE,CAAC;AAEF,eAAO,MAAM,aAAa,QAAO,qBAMhC,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "@emotion/react/jsx-runtime";
3
+ import React, { createContext, useContext, useState } from "react";
4
+ import { AuthStatus } from "../../types.js";
5
+ const AuthStatusContext = createContext(undefined);
6
+ export const AuthStatusProvider = ({ children, }) => {
7
+ const [authStatus, setAuthStatus] = useState(AuthStatus.UNAUTHENTICATED);
8
+ return (_jsx(AuthStatusContext.Provider, { value: { authStatus, setAuthStatus }, children: children }));
9
+ };
10
+ export const useAuthStatus = () => {
11
+ const context = useContext(AuthStatusContext);
12
+ if (context === undefined) {
13
+ throw new Error("useAuthStatus must be used within an AuthStatusProvider");
14
+ }
15
+ return context;
16
+ };
17
+ //# sourceMappingURL=AuthStatusContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthStatusContext.js","sourceRoot":"","sources":["../../../src/shared/providers/AuthStatusContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAOxC,MAAM,iBAAiB,GAAG,aAAa,CACrC,SAAS,CACV,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAA4C,CAAC,EAC1E,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAC1C,UAAU,CAAC,eAAe,CAC3B,CAAC;IAEF,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,YAC7D,QAAQ,GACkB,CAC9B,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,GAA0B,EAAE;IACvD,MAAM,OAAO,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useState } from \"react\";\nimport { AuthStatus } from \"@/types.js\";\n\ninterface AuthStatusContextType {\n authStatus: AuthStatus;\n setAuthStatus: React.Dispatch<React.SetStateAction<AuthStatus>>;\n}\n\nconst AuthStatusContext = createContext<AuthStatusContextType | undefined>(\n undefined,\n);\n\nexport const AuthStatusProvider: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const [authStatus, setAuthStatus] = useState<AuthStatus>(\n AuthStatus.UNAUTHENTICATED,\n );\n\n return (\n <AuthStatusContext.Provider value={{ authStatus, setAuthStatus }}>\n {children}\n </AuthStatusContext.Provider>\n );\n};\n\nexport const useAuthStatus = (): AuthStatusContextType => {\n const context = useContext(AuthStatusContext);\n if (context === undefined) {\n throw new Error(\"useAuthStatus must be used within an AuthStatusProvider\");\n }\n return context;\n};\n"]}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "@civic/auth:0.4.6";
1
+ export declare const VERSION = "@civic/auth:0.4.7";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // This is an auto-generated file. Do not edit.
2
- export const VERSION = "@civic/auth:0.4.6";
2
+ export const VERSION = "@civic/auth:0.4.7";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.4.6\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.4.7\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civic/auth",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",