Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
035f0b3
fix: correct header assignment in initializeEmbeddedSignInFlow function
brionmario Jul 2, 2025
0a48ce3
feat(javascript): add transformBrandingPreferenceToTheme utility and …
brionmario Jul 2, 2025
88144bc
chore(nextjs): add scopes handling in decorateConfigWithNextEnv utility
brionmario Jul 2, 2025
b387c1f
chore: integrate branding support in ThemeProvider and add useBrandin…
brionmario Jul 2, 2025
931f17a
feat(react): enhance organization translations and update rendering l…
brionmario Jul 2, 2025
1b6f159
feat(javascript): add processUsername utility to clean userstore pref…
brionmario Jul 2, 2025
8b440d0
fix(react): adjust spacing and remove border from list items for impr…
brionmario Jul 2, 2025
79f196d
refactor: Update organization management in Asgardeo integration
brionmario Jul 2, 2025
d26360b
feat: add support for custom CSS variable prefixes and enhance theme …
brionmario Jul 2, 2025
58f0919
Refactor components to use theme variables for consistent styling
brionmario Jul 3, 2025
c56bd2a
chore: remove outdated COMPLETE GUIDE.md file
brionmario Jul 3, 2025
6d3b636
refactor: remove unused import for PoundSterling in UserDropdown comp…
brionmario Jul 3, 2025
2cb2f27
chore(react): integrate vendor CSS class prefixing in Typography comp…
brionmario Jul 3, 2025
f29ada3
chore(react): replace button elements with Button component for consi…
brionmario Jul 3, 2025
d4082d5
refactor(react): replace button elements with Button component for co…
brionmario Jul 3, 2025
12a4e27
feat(react): add skeleton loading animation to Avatar component and r…
brionmario Jul 3, 2025
67b694b
chore: add action color properties to theme configuration and update …
brionmario Jul 3, 2025
3be586f
feat(react): add error alert to BaseCreateOrganization component for …
brionmario Jul 3, 2025
22b7773
feat(react): integrate extractUserClaimsFromIdToken for improved user…
brionmario Jul 3, 2025
d5a08b8
chore(react): enhance username processing in processUsername function…
brionmario Jul 3, 2025
9a6c152
chore(react): remove SignOutButton from AuthenticatedActions componen…
brionmario Jul 3, 2025
8039e92
feat(react): implement branding context and provider for enhanced bra…
brionmario Jul 3, 2025
0bbc71a
feat(react): add branding preference handling to enhance user experience
brionmario Jul 3, 2025
53f8e66
feat(nextjs): enhance switchOrganization method to include sessionId …
brionmario Jul 3, 2025
8f2a609
chore(nextjs): clean up import statements in AsgardeoServerProvider c…
brionmario Jul 3, 2025
e140848
fix(react): update background property to backgroundColor and correct…
brionmario Jul 3, 2025
dc54514
feat(nextjs): add getDecodedIdToken method to AsgardeoNextClient and …
brionmario Jul 3, 2025
1196ff6
fix(nextjs): standardize formatting in AsgardeoNextClient and Asgarde…
brionmario Jul 3, 2025
fc80f77
feat: add image configuration support in theme and update related com…
brionmario Jul 3, 2025
c51a9c0
feat(react): enhance BaseSignIn component with custom styles and impr…
brionmario Jul 3, 2025
c0b7ebd
chore: add changeset
brionmario Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/tiny-worms-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@asgardeo/browser': patch
'@asgardeo/express': patch
'@asgardeo/javascript': patch
'@asgardeo/nextjs': patch
'@asgardeo/node': patch
'@asgardeo/react': patch
'@asgardeo/vue': patch
---

Fix B2B components
8 changes: 6 additions & 2 deletions packages/javascript/src/AsgardeoJavaScriptClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
* under the License.
*/

import {AllOrganizationsApiResponse} from './models/organization';
import {AsgardeoClient, SignInOptions, SignOutOptions, SignUpOptions} from './models/client';
import {Config} from './models/config';
import {EmbeddedFlowExecuteRequestPayload, EmbeddedFlowExecuteResponse} from './models/embedded-flow';
import {EmbeddedSignInFlowHandleRequestPayload} from './models/embedded-signin-flow';
import {TokenResponse} from './models/token';
import {Organization} from './models/organization';
import {User, UserProfile} from './models/user';

Expand All @@ -30,13 +32,15 @@ import {User, UserProfile} from './models/user';
* @typeParam T - Configuration type that extends Config.
*/
abstract class AsgardeoJavaScriptClient<T = Config> implements AsgardeoClient<T> {
abstract switchOrganization(organization: Organization): Promise<void>;
abstract switchOrganization(organization: Organization, sessionId?: string): Promise<TokenResponse | Response>;

abstract initialize(config: T): Promise<boolean>;

abstract getUser(options?: any): Promise<User>;

abstract getOrganizations(options?: any): Promise<Organization[]>;
abstract getAllOrganizations(options?: any, sessionId?: string): Promise<AllOrganizationsApiResponse>;

abstract getMyOrganizations(options?: any, sessionId?: string): Promise<Organization[]>;

abstract getCurrentOrganization(sessionId?: string): Promise<Organization | null>;

Expand Down
16 changes: 3 additions & 13 deletions packages/javascript/src/api/getAllOrganizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,9 @@
* under the License.
*/

import {Organization} from '../models/organization';
import {AllOrganizationsApiResponse} from '../models/organization';
import AsgardeoAPIError from '../errors/AsgardeoAPIError';

/**
* Interface for paginated organization response.
*/
export interface PaginatedOrganizationsResponse {
hasMore?: boolean;
nextCursor?: string;
organizations: Organization[];
totalCount?: number;
}

/**
* Configuration for the getAllOrganizations request
*/
Expand Down Expand Up @@ -120,7 +110,7 @@ const getAllOrganizations = async ({
recursive = false,
fetcher,
...requestConfig
}: GetAllOrganizationsConfig): Promise<PaginatedOrganizationsResponse> => {
}: GetAllOrganizationsConfig): Promise<AllOrganizationsApiResponse> => {
try {
new URL(baseUrl);
} catch (error) {
Expand Down Expand Up @@ -150,9 +140,9 @@ const getAllOrganizations = async ({
...requestConfig,
method: 'GET',
headers: {
...requestConfig.headers,
'Content-Type': 'application/json',
Accept: 'application/json',
...requestConfig.headers,
},
};

Expand Down
2 changes: 1 addition & 1 deletion packages/javascript/src/api/getBrandingPreference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const getBrandingPreference = async ({
);

const fetchFn = fetcher || fetch;
const resolvedUrl = `${baseUrl}/api/server/v1/branding-preference${
const resolvedUrl = `${baseUrl}/api/server/v1/branding-preference/resolve${
queryParams.toString() ? `?${queryParams.toString()}` : ''
}`;

Expand Down
7 changes: 5 additions & 2 deletions packages/javascript/src/api/getScim2Me.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import {User} from '../models/user';
import AsgardeoAPIError from '../errors/AsgardeoAPIError';
import processUserUsername from '../utils/processUsername';

/**
* Configuration for the getScim2Me request
Expand Down Expand Up @@ -103,7 +104,7 @@ const getScim2Me = async ({url, baseUrl, fetcher, ...requestConfig}: GetScim2MeC
}

const fetchFn = fetcher || fetch;
const resolvedUrl: string = url ?? `${baseUrl}/scim2/Me`
const resolvedUrl: string = url ?? `${baseUrl}/scim2/Me`;

const requestInit: RequestInit = {
...requestConfig,
Expand All @@ -130,7 +131,9 @@ const getScim2Me = async ({url, baseUrl, fetcher, ...requestConfig}: GetScim2MeC
);
}

return (await response.json()) as User;
const user = (await response.json()) as User;

return processUserUsername(user);
} catch (error) {
if (error instanceof AsgardeoAPIError) {
throw error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ const initializeEmbeddedSignInFlow = async ({
...requestConfig,
method: requestConfig.method || 'POST',
headers: {
...requestConfig.headers,
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
...requestConfig.headers,
},
body: searchParams.toString(),
});
Expand Down
12 changes: 11 additions & 1 deletion packages/javascript/src/i18n/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,18 @@ const translations: I18nTranslations = {
'organization.switcher.members': 'members',
'organization.switcher.member': 'member',
'organization.switcher.create.organization': 'Create Organization',
'organization.switcher.manage.organizations': 'Manage Organization',
'organization.switcher.manage.organizations': 'Manage Organizations',
'organization.switcher.manage.button': 'Manage',
'organization.switcher.organizations.title': 'Organizations',
'organization.switcher.switch.button': 'Switch',
'organization.switcher.no.access': 'No Access',
'organization.switcher.status.label': 'Status:',
'organization.switcher.showing.count': 'Showing {showing} of {total} organizations',
'organization.switcher.refresh.button': 'Refresh',
'organization.switcher.load.more': 'Load More Organizations',
'organization.switcher.loading.more': 'Loading...',
'organization.switcher.no.organizations': 'No organizations found',
'organization.switcher.error.prefix': 'Error:',
'organization.profile.title': 'Organization Profile',
'organization.profile.loading': 'Loading organization...',
'organization.profile.error': 'Failed to load organization',
Expand Down
9 changes: 4 additions & 5 deletions packages/javascript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ export {default as executeEmbeddedSignUpFlow} from './api/executeEmbeddedSignUpF
export {default as getUserInfo} from './api/getUserInfo';
export {default as getScim2Me, GetScim2MeConfig} from './api/getScim2Me';
export {default as getSchemas, GetSchemasConfig} from './api/getSchemas';
export {
default as getAllOrganizations,
PaginatedOrganizationsResponse,
GetAllOrganizationsConfig,
} from './api/getAllOrganizations';
export {default as getAllOrganizations, GetAllOrganizationsConfig} from './api/getAllOrganizations';
export {
default as createOrganization,
CreateOrganizationPayload,
Expand All @@ -53,6 +49,7 @@ export {default as AsgardeoAPIError} from './errors/AsgardeoAPIError';
export {default as AsgardeoRuntimeError} from './errors/AsgardeoRuntimeError';
export {AsgardeoAuthException} from './errors/exception';

export {AllOrganizationsApiResponse} from './models/organization';
export {
EmbeddedSignInFlowInitiateResponse,
EmbeddedSignInFlowStatus,
Expand Down Expand Up @@ -115,6 +112,7 @@ export {default as AsgardeoJavaScriptClient} from './AsgardeoJavaScriptClient';
export {default as createTheme} from './theme/createTheme';
export {ThemeColors, ThemeConfig, Theme, ThemeMode, ThemeDetection} from './theme/types';

export {default as processUsername} from './utils/processUsername';
export {default as deepMerge} from './utils/deepMerge';
export {default as deriveOrganizationHandleFromBaseUrl} from './utils/deriveOrganizationHandleFromBaseUrl';
export {default as extractUserClaimsFromIdToken} from './utils/extractUserClaimsFromIdToken';
Expand All @@ -132,5 +130,6 @@ export {default as resolveFieldType} from './utils/resolveFieldType';
export {default as resolveFieldName} from './utils/resolveFieldName';
export {default as processOpenIDScopes} from './utils/processOpenIDScopes';
export {default as withVendorCSSClassPrefix} from './utils/withVendorCSSClassPrefix';
export {default as transformBrandingPreferenceToTheme} from './utils/transformBrandingPreferenceToTheme';

export {default as StorageManager} from './StorageManager';
22 changes: 17 additions & 5 deletions packages/javascript/src/models/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@
* under the License.
*/

import {EmbeddedFlowExecuteRequestConfig, EmbeddedFlowExecuteRequestPayload, EmbeddedFlowExecuteResponse} from './embedded-flow';
import {AllOrganizationsApiResponse} from '../models/organization';
import {
EmbeddedFlowExecuteRequestConfig,
EmbeddedFlowExecuteRequestPayload,
EmbeddedFlowExecuteResponse,
} from './embedded-flow';
import {EmbeddedSignInFlowHandleRequestPayload} from './embedded-signin-flow';
import {Organization} from './organization';
import {User, UserProfile} from './user';
import {TokenResponse} from './token';

export type SignInOptions = Record<string, unknown>;
export type SignOutOptions = Record<string, unknown>;
Expand All @@ -37,11 +43,13 @@ export type SignUpOptions = Record<string, unknown>;
*/
export interface AsgardeoClient<T> {
/**
* Gets the users associated organizations.
* Gets the current signed-in user's associated organizations.
*
* @returns Associated organizations.
*/
getOrganizations(options?: any): Promise<Organization[]>;
getMyOrganizations(options?: any, sessionId?: string): Promise<Organization[]>;

getAllOrganizations(options?: any, sessionId?: string): Promise<AllOrganizationsApiResponse>;

/**
* Gets the current organization of the user.
Expand All @@ -55,7 +63,7 @@ export interface AsgardeoClient<T> {
* @param organization - The organization to switch to.
* @returns A promise that resolves when the switch is complete.
*/
switchOrganization(organization: Organization): Promise<void>;
switchOrganization(organization: Organization, sessionId?: string): Promise<TokenResponse | Response> ;

getConfiguration(): T;

Expand Down Expand Up @@ -147,7 +155,11 @@ export interface AsgardeoClient<T> {
* @param afterSignOut - Callback function to be executed after sign-out is complete.
* @returns A promise that resolves to true if sign-out is successful
*/
signOut(options?: SignOutOptions, sessionId?: string, afterSignOut?: (afterSignOutUrl: string) => void): Promise<string>;
signOut(
options?: SignOutOptions,
sessionId?: string,
afterSignOut?: (afterSignOutUrl: string) => void,
): Promise<string>;

/**
* Initiates a redirection-based sign-up process for the user.
Expand Down
10 changes: 10 additions & 0 deletions packages/javascript/src/models/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ export interface I18nTranslations {
'organization.switcher.create.organization': string;
'organization.switcher.manage.organizations': string;
'organization.switcher.manage.button': string;
'organization.switcher.organizations.title': string;
'organization.switcher.switch.button': string;
'organization.switcher.no.access': string;
'organization.switcher.status.label': string;
'organization.switcher.showing.count': string;
'organization.switcher.refresh.button': string;
'organization.switcher.load.more': string;
'organization.switcher.loading.more': string;
'organization.switcher.no.organizations': string;
'organization.switcher.error.prefix': string;
'organization.profile.title': string;
'organization.profile.loading': string;
'organization.profile.error': string;
Expand Down
10 changes: 10 additions & 0 deletions packages/javascript/src/models/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ export interface Organization {
ref?: string;
status?: string;
}

/**
* Interface for paginated organization response.
*/
export interface AllOrganizationsApiResponse {
hasMore?: boolean;
nextCursor?: string;
organizations: Organization[];
totalCount?: number;
}
98 changes: 98 additions & 0 deletions packages/javascript/src/theme/createTheme.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import {describe, it, expect} from 'vitest';
import createTheme from './createTheme';

describe('createTheme', () => {
it('should include vars property with CSS variable references', () => {
const theme = createTheme();

expect(theme.vars).toBeDefined();
expect(theme.vars.colors.primary.main).toBe('var(--asgardeo-color-primary-main)');
expect(theme.vars.colors.primary.contrastText).toBe('var(--asgardeo-color-primary-contrastText)');
expect(theme.vars.spacing.unit).toBe('var(--asgardeo-spacing-unit)');
expect(theme.vars.borderRadius.small).toBe('var(--asgardeo-border-radius-small)');
expect(theme.vars.shadows.medium).toBe('var(--asgardeo-shadow-medium)');
});

it('should have matching structure between cssVariables and vars', () => {
const theme = createTheme();

// Check that cssVariables has corresponding entries for vars
expect(theme.cssVariables['--asgardeo-color-primary-main']).toBeDefined();
expect(theme.cssVariables['--asgardeo-spacing-unit']).toBeDefined();
expect(theme.cssVariables['--asgardeo-border-radius-small']).toBeDefined();
expect(theme.cssVariables['--asgardeo-shadow-medium']).toBeDefined();
});

it('should work with custom theme configurations', () => {
const customTheme = createTheme({
colors: {
primary: {
main: '#custom-color',
},
},
});

// vars should still reference CSS variables, not the actual values
expect(customTheme.vars.colors.primary.main).toBe('var(--asgardeo-color-primary-main)');
// but cssVariables should have the custom value
expect(customTheme.cssVariables['--asgardeo-color-primary-main']).toBe('#custom-color');
});

it('should work with dark theme', () => {
const darkTheme = createTheme({}, true);

expect(darkTheme.vars.colors.primary.main).toBe('var(--asgardeo-color-primary-main)');
expect(darkTheme.vars.colors.background.surface).toBe('var(--asgardeo-color-background-surface)');

// Should have dark theme values in cssVariables
expect(darkTheme.cssVariables['--asgardeo-color-background-surface']).toBe('#121212');
});

it('should use custom CSS variable prefix when provided', () => {
const customTheme = createTheme({
cssVarPrefix: 'custom-app',
colors: {
primary: {
main: '#custom-color',
},
},
});

// Should use custom prefix in CSS variables
expect(customTheme.cssVariables['--custom-app-color-primary-main']).toBe('#custom-color');
expect(customTheme.cssVariables['--custom-app-spacing-unit']).toBe('8px');

// Should use custom prefix in vars
expect(customTheme.vars.colors.primary.main).toBe('var(--custom-app-color-primary-main)');
expect(customTheme.vars.spacing.unit).toBe('var(--custom-app-spacing-unit)');

// Should not have old asgardeo prefixed variables
expect(customTheme.cssVariables['--asgardeo-color-primary-main']).toBeUndefined();
});

it('should use VendorConstants.VENDOR_PREFIX as default prefix', () => {
const theme = createTheme();

// Should use default prefix from VendorConstants
expect(theme.cssVariables['--asgardeo-color-primary-main']).toBeDefined();
expect(theme.vars.colors.primary.main).toBe('var(--asgardeo-color-primary-main)');
});
});
Loading
Loading