Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
117 changes: 117 additions & 0 deletions packages/javascript/src/api/createUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* 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 {User} from '../models/user';
import AsgardeoAPIError from '../errors/AsgardeoAPIError';

/**
* Configuration for the createUser request
*/
export interface CreateUserConfig extends Omit<RequestInit, 'method' | 'body'> {
/**
* The absolute API endpoint.
* Defaults to https://api.asgardeo.io/t/dxlab/scim2/Users
*/
url?: string;
/**
* The base path of the API endpoint (e.g., https://api.asgardeo.io/t/dxlab)
*/
baseUrl?: string;
/**
* The user object to create (SCIM2 User schema)
*/
payload: any;
/**
* Optional custom fetcher function.
* If not provided, native fetch will be used
*/
fetcher?: (url: string, config: RequestInit) => Promise<Response>;
}

/**
* Creates a new user at the SCIM2 Users endpoint.
*
* @param config - Configuration object with URL, payload and optional request config.
* @returns A promise that resolves with the created user profile information.
* @example
* ```typescript
* await createUser({
* url: "https://api.asgardeo.io/t/dxlab/scim2/Users",
* payload: { ... }
* });
* ```
*/
const createUser = async ({url, baseUrl, payload, fetcher, ...requestConfig}: CreateUserConfig): Promise<User> => {
try {
new URL(url ?? baseUrl);
} catch (error) {
throw new AsgardeoAPIError(
`Invalid URL provided. ${error?.toString()}`,
'createUser-ValidationError-001',
'javascript',
400,
'The provided `url` or `baseUrl` path does not adhere to the URL schema.',
);
}

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

const requestInit: RequestInit = {
method: 'POST',
...requestConfig,
headers: {
...requestConfig.headers,
'Content-Type': 'application/scim+json',
Accept: 'application/json',
},
body: JSON.stringify(payload),
};

try {
const response: Response = await fetchFn(resolvedUrl, requestInit);

if (!response?.ok) {
const errorText = await response.text();

throw new AsgardeoAPIError(
`Failed to create user: ${errorText}`,
'createUser-ResponseError-001',
'javascript',
response.status,
response.statusText,
);
}

return (await response.json()) as User;
} catch (error) {
if (error instanceof AsgardeoAPIError) {
throw error;
}

throw new AsgardeoAPIError(
error?.response?.data?.detail || 'An error occurred while creating the user. Please try again.',
'createUser-NetworkError-001',
'javascript',
error?.data?.status,
'Network Error',
);
}
};

export default createUser;
97 changes: 97 additions & 0 deletions packages/javascript/src/api/getUserstores.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* 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 AsgardeoAPIError from '../errors/AsgardeoAPIError';
import {Userstore, UserstoreProperty} from '../models/userstore';

export interface GetUserstoresConfig extends Omit<RequestInit, 'method'> {
url?: string;
baseUrl?: string;
fetcher?: (url: string, config: RequestInit) => Promise<Response>;
requiredAttributes?: string;
}

/**
* Retrieves the userstores from the specified endpoint.
* @param config - Request configuration object.
* @returns A promise that resolves with the userstores information.
*/
const getUserstores = async ({
url,
baseUrl,
fetcher,
requiredAttributes,
...requestConfig
}: GetUserstoresConfig): Promise<Userstore[]> => {
try {
new URL(url ?? baseUrl);
} catch (error) {
throw new AsgardeoAPIError(
`Invalid URL provided. ${error?.toString()}`,
'getUserstores-ValidationError-001',
'javascript',
400,
'The provided `url` or `baseUrl` path does not adhere to the URL schema.',
);
}

const fetchFn = fetcher || fetch;
let resolvedUrl: string = url ?? `${baseUrl}/api/server/v1/userstores`;
if (requiredAttributes) {
const sep = resolvedUrl.includes('?') ? '&' : '?';
resolvedUrl += `${sep}requiredAttributes=${encodeURIComponent(requiredAttributes)}`;
}

const requestInit: RequestInit = {
...requestConfig,
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...requestConfig.headers,
},
};

try {
const response: Response = await fetchFn(resolvedUrl, requestInit);
if (!response?.ok) {
const errorText = await response.text();
throw new AsgardeoAPIError(
errorText || 'Failed to fetch userstores.',
'getUserstores-ResponseError-001',
'javascript',
response.status,
response.statusText,
);
}
return (await response.json()) as Userstore[];
} catch (error) {
if (error instanceof AsgardeoAPIError) {
throw error;
}
throw new AsgardeoAPIError(
error?.response?.data?.detail || 'An error occurred while fetching userstores. Please try again.',
'getUserstores-NetworkError-001',
'javascript',
error?.data?.status,
'Network Error',
);
}
};

export default getUserstores;
9 changes: 9 additions & 0 deletions packages/javascript/src/i18n/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ const translations: I18nTranslations = {
'organization.create.creating': 'Creating...',
'organization.create.cancel': 'Cancel',

/* |---------------------------------------------------------------| */
/* | User Creation | */
/* |---------------------------------------------------------------| */

'user.create.cancel': 'Cancel',
'user.create.submit': 'Create User',
'user.create.submitting': 'Creating...',
'user.create.generic.error': 'An error occurred while creating the user. Please try again.',

/* |---------------------------------------------------------------| */
/* | Messages | */
/* |---------------------------------------------------------------| */
Expand Down
7 changes: 6 additions & 1 deletion packages/javascript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export {default as getOrganization, OrganizationDetails, GetOrganizationConfig}
export {default as updateOrganization, createPatchOperations, UpdateOrganizationConfig} from './api/updateOrganization';
export {default as updateMeProfile, UpdateMeProfileConfig} from './api/updateMeProfile';
export {default as getBrandingPreference, GetBrandingPreferenceConfig} from './api/getBrandingPreference';
export {default as createUser, CreateUserConfig} from './api/createUser';
export {default as getUserstores, GetUserstoresConfig} from './api/getUserstores';

export {default as ApplicationNativeAuthenticationConstants} from './constants/ApplicationNativeAuthenticationConstants';
export {default as TokenConstants} from './constants/TokenConstants';
Expand All @@ -63,6 +65,7 @@ export {
EmbeddedSignInFlowAuthenticatorPromptType,
EmbeddedSignInFlowAuthenticatorKnownIdPType,
} from './models/embedded-signin-flow';
export {UserstoreProperty, Userstore} from './models/userstore';
export {
EmbeddedFlowType,
EmbeddedFlowStatus,
Expand Down Expand Up @@ -112,7 +115,7 @@ export {
BrandingOrganizationDetails,
UrlsConfig,
} from './models/branding-preference';
export {Schema, SchemaAttribute, WellKnownSchemaIds, FlattenedSchema} from './models/scim2-schema';
export {Schema, SchemaAttribute, WellKnownSchemaIds, FlattenedSchema, ProfileSchemaType} from './models/scim2-schema';
export {RecursivePartial} from './models/utility-types';
export {FieldType} from './models/field';
export {I18nBundle, I18nTranslations, I18nMetadata} from './models/i18n';
Expand All @@ -123,10 +126,12 @@ export {default as createTheme} from './theme/createTheme';
export {ThemeColors, ThemeConfig, Theme, ThemeMode, ThemeDetection} from './theme/types';

export {default as bem} from './utils/bem';
export {default as getAttributeProfileSchema} from './utils/getAttributeProfileSchema';
export {default as formatDate} from './utils/formatDate';
export {default as processUsername} from './utils/processUsername';
export {default as deepMerge} from './utils/deepMerge';
export {default as deriveOrganizationHandleFromBaseUrl} from './utils/deriveOrganizationHandleFromBaseUrl';
export {default as detectUserstoreEnvironment} from './utils/detectUserstoreEnvironment';
export {default as extractUserClaimsFromIdToken} from './utils/extractUserClaimsFromIdToken';
export {default as extractPkceStorageKeyFromState} from './utils/extractPkceStorageKeyFromState';
export {default as flattenUserSchema} from './utils/flattenUserSchema';
Expand Down
9 changes: 9 additions & 0 deletions packages/javascript/src/models/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ export interface I18nTranslations {
'organization.create.creating': string;
'organization.create.cancel': string;

/* |---------------------------------------------------------------| */
/* | User Creation | */
/* |---------------------------------------------------------------| */

'user.create.cancel': string;
'user.create.submit': string;
'user.create.submitting': string;
'user.create.generic.error': string;

/* |---------------------------------------------------------------| */
/* | Messages | */
/* |---------------------------------------------------------------| */
Expand Down
8 changes: 8 additions & 0 deletions packages/javascript/src/models/scim2-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export interface SchemaAttribute {
supportedByDefault?: string;
sharedProfileValueResolvingMethod?: string;
subAttributes?: SchemaAttribute[];
profiles: {
[key: string]: {
required?: boolean;
supportedByDefault?: boolean;
};
};
}

/**
Expand Down Expand Up @@ -67,3 +73,5 @@ export enum WellKnownSchemaIds {
/** Custom User Schema */
CustomUser = 'urn:scim:schemas:extension:custom:User',
}

export type ProfileSchemaType = 'console' | 'endUser' | 'selfRegistration';
33 changes: 33 additions & 0 deletions packages/javascript/src/models/userstore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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.
*/

export interface UserstoreProperty {
name: string;
value: string;
}

export interface Userstore {
id: string;
name: string;
enabled: boolean;
description?: string;
isLocal: boolean;
self: string;
typeName: string;
properties?: UserstoreProperty[];
}
Loading
Loading