From 679278aee01d4d669edbc96fff6b01284ea15fa7 Mon Sep 17 00:00:00 2001 From: Brion Date: Mon, 4 Aug 2025 15:44:44 +0530 Subject: [PATCH] Refactor aggregate-changelogs.js for improved readability and consistency - Consolidated array declaration for SKIP_PACKAGES into a single line. - Removed unnecessary line breaks and adjusted spacing for function definitions and conditions. - Enhanced code clarity by simplifying the structure of the findChangelogs function. --- .github/workflows/release.yml | 5 +- package.json | 2 +- packages/react/src/AsgardeoReactClient.ts | 73 ++++++++++--------- .../contexts/Asgardeo/AsgardeoProvider.tsx | 63 +++++++++++++--- scripts/aggregate-changelogs.js | 31 ++------ 5 files changed, 102 insertions(+), 72 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00b086d2..0075f479 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,8 @@ env: jobs: release: name: 📦 Release - if: "!contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci')" + if: + "!contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci')" runs-on: ubuntu-latest strategy: matrix: @@ -60,7 +61,7 @@ jobs: id: changesets uses: changesets/action@v1 with: - title: "[Release] [GitHub Action] Update package versions" + title: '[Release] [GitHub Action] Update package versions' publish: pnpm publish:packages version: pnpm version:packages commit: "[WSO2 Release] [GitHub Action] [Release] [skip ci] update package versions" diff --git a/package.json b/package.json index b7205c97..a10805b9 100644 --- a/package.json +++ b/package.json @@ -41,4 +41,4 @@ "publishConfig": { "access": "restricted" } -} \ No newline at end of file +} diff --git a/packages/react/src/AsgardeoReactClient.ts b/packages/react/src/AsgardeoReactClient.ts index 28f2d342..6ca76f1b 100644 --- a/packages/react/src/AsgardeoReactClient.ts +++ b/packages/react/src/AsgardeoReactClient.ts @@ -125,37 +125,41 @@ class AsgardeoReactClient e } async getDecodedIdToken(sessionId?: string): Promise { - return this.asgardeo.getDecodedIdToken(sessionId); + return this.withLoading(async () => { + return this.asgardeo.getDecodedIdToken(sessionId); + }); } async getUserProfile(options?: any): Promise { - try { - let baseUrl = options?.baseUrl; + return this.withLoading(async () => { + try { + let baseUrl = options?.baseUrl; - if (!baseUrl) { - const configData = await this.asgardeo.getConfigData(); - baseUrl = configData?.baseUrl; - } + if (!baseUrl) { + const configData = await this.asgardeo.getConfigData(); + baseUrl = configData?.baseUrl; + } - const profile = await getScim2Me({baseUrl}); - const schemas = await getSchemas({baseUrl}); + const profile = await getScim2Me({baseUrl}); + const schemas = await getSchemas({baseUrl}); - const processedSchemas = flattenUserSchema(schemas); + const processedSchemas = flattenUserSchema(schemas); - const output = { - schemas: processedSchemas, - flattenedProfile: generateFlattenedUserProfile(profile, processedSchemas), - profile, - }; + const output = { + schemas: processedSchemas, + flattenedProfile: generateFlattenedUserProfile(profile, processedSchemas), + profile, + }; - return output; - } catch (error) { - return { - schemas: [], - flattenedProfile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), - profile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), - }; - } + return output; + } catch (error) { + return { + schemas: [], + flattenedProfile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), + profile: extractUserClaimsFromIdToken(await this.getDecodedIdToken()), + }; + } + }); } override async getMyOrganizations(options?: any, sessionId?: string): Promise { @@ -201,13 +205,14 @@ class AsgardeoReactClient e } override async getCurrentOrganization(): Promise { - const idToken: IdToken = await this.getDecodedIdToken(); - - return { - orgHandle: idToken?.org_handle, - name: idToken?.org_name, - id: idToken?.org_id, - }; + return this.withLoading(async () => { + const idToken: IdToken = await this.getDecodedIdToken(); + return { + orgHandle: idToken?.org_handle, + name: idToken?.org_name, + id: idToken?.org_id, + }; + }); } override async switchOrganization(organization: Organization, sessionId?: string): Promise { @@ -258,8 +263,8 @@ class AsgardeoReactClient e return this.asgardeo.isInitialized(); } - override isSignedIn(): Promise { - return this.asgardeo.isSignedIn(); + override async isSignedIn(): Promise { + return await this.asgardeo.isSignedIn(); } override getConfiguration(): T { @@ -355,7 +360,9 @@ class AsgardeoReactClient e } override async getAccessToken(sessionId?: string): Promise { - return this.asgardeo.getAccessToken(sessionId); + return this.withLoading(async () => { + return this.asgardeo.getAccessToken(sessionId); + }); } } diff --git a/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx b/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx index 07038768..ea534fef 100644 --- a/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx +++ b/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx @@ -26,6 +26,7 @@ import { getBrandingPreference, GetBrandingPreferenceConfig, BrandingPreference, + IdToken, } from '@asgardeo/browser'; import {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react'; import AsgardeoContext from './AsgardeoContext'; @@ -88,6 +89,8 @@ const AsgardeoProvider: FC> = ({ ...rest, }); + const [isUpdatingSession, setIsUpdatingSession] = useState(false); + // Branding state const [brandingPreference, setBrandingPreference] = useState(null); const [isBrandingLoading, setIsBrandingLoading] = useState(false); @@ -129,13 +132,17 @@ const AsgardeoProvider: FC> = ({ (async (): Promise => { // User is already authenticated. Skip... - if (await asgardeo.isSignedIn()) { - await updateSession(); + const isAlreadySignedIn: boolean = await asgardeo.isSignedIn(); + if (isAlreadySignedIn) { + await updateSession(); return; } - if (hasAuthParams(new URL(window.location.href), afterSignInUrl)) { + const currentUrl: URL = new URL(window.location.href); + const hasAuthParamsResult: boolean = hasAuthParams(currentUrl, afterSignInUrl); + + if (hasAuthParamsResult) { try { await signIn( {callOnlyOnRedirect: true}, @@ -143,13 +150,14 @@ const AsgardeoProvider: FC> = ({ // authParams?.sessionState, // authParams?.state, ); - // setError(null); } catch (error) { if (error && Object.prototype.hasOwnProperty.call(error, 'code')) { // setError(error); } } + } else { + // TODO: Add a debug log to indicate that the user is not signed in } })(); }, []); @@ -177,6 +185,8 @@ const AsgardeoProvider: FC> = ({ clearInterval(interval); } }, 1000); + } else { + // TODO: Add a debug log to indicate that the user is already signed in. } } catch (error) { setIsSignedInSync(false); @@ -207,8 +217,12 @@ const AsgardeoProvider: FC> = ({ */ useEffect(() => { const checkLoadingState = (): void => { - const loadingState = asgardeo.isLoading(); - setIsLoadingSync(loadingState); + // Don't override loading state during critical session updates + if (isUpdatingSession) { + return; + } + + setIsLoadingSync(asgardeo.isLoading()); }; // Initial check @@ -220,25 +234,44 @@ const AsgardeoProvider: FC> = ({ return (): void => { clearInterval(interval); }; - }, [asgardeo]); + }, [asgardeo, isLoadingSync, isSignedInSync, isUpdatingSession]); const updateSession = async (): Promise => { try { + // Set flag to prevent loading state tracking from interfering + setIsUpdatingSession(true); setIsLoadingSync(true); let _baseUrl: string = baseUrl; + const decodedToken: IdToken = await asgardeo.getDecodedIdToken(); + // If there's a `user_org` claim in the ID token, // Treat this login as a organization login. - if ((await asgardeo.getDecodedIdToken())?.['user_org']) { + if (decodedToken?.['user_org']) { _baseUrl = `${(await asgardeo.getConfiguration()).baseUrl}/o`; setBaseUrl(_baseUrl); } - setUser(await asgardeo.getUser({baseUrl: _baseUrl})); - setUserProfile(await asgardeo.getUserProfile({baseUrl: _baseUrl})); - setCurrentOrganization(await asgardeo.getCurrentOrganization()); - setMyOrganizations(await asgardeo.getMyOrganizations()); + const user: User = await asgardeo.getUser({baseUrl: _baseUrl}); + const userProfile: UserProfile = await asgardeo.getUserProfile({baseUrl: _baseUrl}); + const currentOrganization: Organization = await asgardeo.getCurrentOrganization(); + const myOrganizations: Organization[] = await asgardeo.getMyOrganizations(); + + // Update user data first + setUser(user); + setUserProfile(userProfile); + setCurrentOrganization(currentOrganization); + setMyOrganizations(myOrganizations); + + // CRITICAL: Update sign-in status BEFORE setting loading to false + // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false + const currentSignInStatus = await asgardeo.isSignedIn(); + setIsSignedInSync(await asgardeo.isSignedIn()); + } catch (error) { + // TODO: Add an error log. } finally { + // Clear the flag and set final loading state + setIsUpdatingSession(false); setIsLoadingSync(asgardeo.isLoading()); } }; @@ -302,6 +335,7 @@ const AsgardeoProvider: FC> = ({ const signIn = async (...args: any): Promise => { try { + setIsUpdatingSession(true); setIsLoadingSync(true); const response: User = await asgardeo.signIn(...args); @@ -313,12 +347,14 @@ const AsgardeoProvider: FC> = ({ } catch (error) { throw new Error(`Error while signing in: ${error}`); } finally { + setIsUpdatingSession(false); setIsLoadingSync(asgardeo.isLoading()); } }; const signInSilently = async (options?: SignInOptions): Promise => { try { + setIsUpdatingSession(true); setIsLoadingSync(true); const response: User | boolean = await asgardeo.signInSilently(options); @@ -335,12 +371,14 @@ const AsgardeoProvider: FC> = ({ 'An error occurred while trying to sign in silently.', ); } finally { + setIsUpdatingSession(false); setIsLoadingSync(asgardeo.isLoading()); } }; const switchOrganization = async (organization: Organization): Promise => { try { + setIsUpdatingSession(true); setIsLoadingSync(true); await asgardeo.switchOrganization(organization); @@ -355,6 +393,7 @@ const AsgardeoProvider: FC> = ({ 'An error occurred while switching to the specified organization.', ); } finally { + setIsUpdatingSession(false); setIsLoadingSync(asgardeo.isLoading()); } }; diff --git a/scripts/aggregate-changelogs.js b/scripts/aggregate-changelogs.js index 6183897d..44f280cf 100644 --- a/scripts/aggregate-changelogs.js +++ b/scripts/aggregate-changelogs.js @@ -26,35 +26,19 @@ const path = require('path'); const rootDir = process.cwd(); const outputFile = path.join(rootDir, 'CHANGELOG.md'); - // List of package or directory names to skip when aggregating changelogs -const SKIP_PACKAGES = [ - '__legacy__', - 'node_modules', - 'dist', - 'build', - 'coverage', - 'scripts', - 'docs', -]; +const SKIP_PACKAGES = ['__legacy__', 'node_modules', 'dist', 'build', 'coverage', 'scripts', 'docs']; -const findChangelogs = (dir) => { +const findChangelogs = dir => { let changelogs = []; - const entries = fs.readdirSync(dir, { withFileTypes: true }); + const entries = fs.readdirSync(dir, {withFileTypes: true}); for (const entry of entries) { const fullPath = path.join(dir, entry.name); - if ( - entry.isDirectory() && - !SKIP_PACKAGES.includes(entry.name) - ) { + if (entry.isDirectory() && !SKIP_PACKAGES.includes(entry.name)) { changelogs = changelogs.concat(findChangelogs(fullPath)); - } else if ( - entry.isFile() && - entry.name === 'CHANGELOG.md' && - fullPath !== outputFile - ) { + } else if (entry.isFile() && entry.name === 'CHANGELOG.md' && fullPath !== outputFile) { // Check if the changelog is inside a skipped package const relPath = path.relative(rootDir, fullPath); const parts = relPath.split(path.sep); @@ -65,8 +49,7 @@ const findChangelogs = (dir) => { } return changelogs; -} - +}; const aggregate = () => { const changelogFiles = findChangelogs(rootDir); @@ -93,6 +76,6 @@ const aggregate = () => { fs.writeFileSync(outputFile, toc + output); console.log(`Aggregated ${changelogFiles.length} changelogs into ${outputFile}`); -} +}; aggregate();