diff --git a/.changeset/tricky-rooms-try.md b/.changeset/tricky-rooms-try.md new file mode 100644 index 00000000..efc7a387 --- /dev/null +++ b/.changeset/tricky-rooms-try.md @@ -0,0 +1,6 @@ +--- +'@asgardeo/javascript': patch +'@asgardeo/react': patch +--- + +Update types and improve type safety across components and models diff --git a/.github/workflows/npm-audit.yml b/.github/workflows/npm-audit.yml index b0f1ccde..7219cdaa 100644 --- a/.github/workflows/npm-audit.yml +++ b/.github/workflows/npm-audit.yml @@ -34,6 +34,7 @@ jobs: strategy: matrix: node-version: [lts/*] + pnpm-version: [latest] steps: - name: ⬇️ Checkout id: checkout @@ -49,7 +50,7 @@ jobs: id: setup-pnpm uses: pnpm/action-setup@v2.1.0 with: - version: latest + version: ${{ matrix.pnpm-version }} run_install: false - name: 🧩 Install Dependencies diff --git a/.github/workflows/pr-builder.yml b/.github/workflows/pr-builder.yml index 4eeccda0..fb7e7771 100644 --- a/.github/workflows/pr-builder.yml +++ b/.github/workflows/pr-builder.yml @@ -20,6 +20,7 @@ jobs: strategy: matrix: node-version: [lts/*] + pnpm-version: [latest] steps: - name: ⬇️ Checkout id: checkout @@ -44,7 +45,7 @@ jobs: id: setup-pnpm uses: pnpm/action-setup@v2.1.0 with: - version: latest + version: ${{ matrix.pnpm-version }} run_install: false - name: 🎈 Get pnpm store directory @@ -75,6 +76,7 @@ jobs: strategy: matrix: node-version: [lts/*] + pnpm-version: [latest] steps: - name: ⬇️ Checkout id: checkout @@ -98,7 +100,7 @@ jobs: - name: 🥡 Setup pnpm uses: pnpm/action-setup@v2.1.0 with: - version: latest + version: ${{ matrix.pnpm-version }} run_install: false - name: 🎈 Get pnpm store directory @@ -118,7 +120,7 @@ jobs: - name: 🧩 Install Dependencies id: install-dependencies run: pnpm install - + - name: 🏗️ Build id: build run: pnpm build @@ -133,6 +135,7 @@ jobs: strategy: matrix: node-version: [lts/*] + pnpm-version: [latest] steps: - name: ⬇️ Checkout id: checkout @@ -150,7 +153,7 @@ jobs: - name: 🥡 Setup pnpm uses: pnpm/action-setup@v2.1.0 with: - version: latest + version: ${{ matrix.pnpm-version }} run_install: false - name: 🎈 Get pnpm store directory @@ -170,7 +173,7 @@ jobs: - name: 🧩 Install Dependencies id: install-dependencies run: pnpm install - + - name: 🏗️ Build id: build run: pnpm build @@ -186,6 +189,7 @@ jobs: strategy: matrix: node-version: [lts/*] + pnpm-version: [latest] steps: - name: ⬇️ Checkout id: checkout @@ -200,7 +204,7 @@ jobs: - name: 🥡 Setup pnpm uses: pnpm/action-setup@v2.1.0 with: - version: latest + version: ${{ matrix.pnpm-version }} run_install: false - name: 🎈 Get pnpm store directory diff --git a/packages/javascript/src/models/config.ts b/packages/javascript/src/models/config.ts index 297a6d4d..e72a8756 100644 --- a/packages/javascript/src/models/config.ts +++ b/packages/javascript/src/models/config.ts @@ -104,7 +104,7 @@ export interface BaseConfig extends WithPreferences { * The client ID obtained from the Asgardeo application registration. * This is used to identify your application during authentication. */ - clientId: string | undefined; + clientId?: string | undefined; /** * Optional client secret for the application. diff --git a/packages/javascript/src/models/embedded-flow.ts b/packages/javascript/src/models/embedded-flow.ts index a0d55ea1..07495b87 100644 --- a/packages/javascript/src/models/embedded-flow.ts +++ b/packages/javascript/src/models/embedded-flow.ts @@ -51,9 +51,9 @@ export interface EmbeddedSignUpFlowData { export interface EmbeddedFlowComponent { components: EmbeddedFlowComponent[]; - config: Record; + config: Record; id: string; - type: EmbeddedFlowComponentType; + type: EmbeddedFlowComponentType | string; variant?: string; } diff --git a/packages/javascript/src/models/v2/embedded-signin-flow-v2.ts b/packages/javascript/src/models/v2/embedded-signin-flow-v2.ts index 03e2ba2c..33c98ba8 100644 --- a/packages/javascript/src/models/v2/embedded-signin-flow-v2.ts +++ b/packages/javascript/src/models/v2/embedded-signin-flow-v2.ts @@ -29,11 +29,23 @@ export enum EmbeddedSignInFlowTypeV2 { View = 'VIEW', } +/** + * Extended response structure for the embedded sign-in flow V2. + * @remarks This response is only done from the SDK level. + * @experimental + */ +export interface ExtendedEmbeddedSignInFlowResponseV2 { + /** + * The URL to redirect the user after completing the sign-in flow. + */ + redirectUrl?: string; +} + /** * Response structure for the new Asgardeo V2 embedded sign-in flow. * @experimental */ -export interface EmbeddedSignInFlowResponseV2 { +export interface EmbeddedSignInFlowResponseV2 extends ExtendedEmbeddedSignInFlowResponseV2 { flowId: string; flowStatus: EmbeddedSignInFlowStatusV2; type: EmbeddedSignInFlowTypeV2; diff --git a/packages/nextjs/src/client/components/actions/SignInButton/SignInButton.tsx b/packages/nextjs/src/client/components/actions/SignInButton/SignInButton.tsx index 00da5e2a..4f25cbd9 100644 --- a/packages/nextjs/src/client/components/actions/SignInButton/SignInButton.tsx +++ b/packages/nextjs/src/client/components/actions/SignInButton/SignInButton.tsx @@ -77,7 +77,7 @@ const SignInButton = forwardRef( if (signInUrl) { router.push(signInUrl); } else { - await signIn(signInOptions); + signIn && await signIn(signInOptions); } if (onClick) { diff --git a/packages/nextjs/src/client/components/actions/SignUpButton/SignUpButton.tsx b/packages/nextjs/src/client/components/actions/SignUpButton/SignUpButton.tsx index 9729c5db..61077926 100644 --- a/packages/nextjs/src/client/components/actions/SignUpButton/SignUpButton.tsx +++ b/packages/nextjs/src/client/components/actions/SignUpButton/SignUpButton.tsx @@ -88,7 +88,7 @@ const SignUpButton: ForwardRefExoticComponent = ({size = 'medium', variant = 'outlined', ...rest const {signIn, afterSignInUrl} = useAsgardeo(); const handleInitialize = async (): Promise => - await signIn({ + signIn && + (await signIn({ flowId: '', selectedAuthenticator: { authenticatorId: '', params: {}, }, - }); + })); const handleOnSubmit = async ( payload: EmbeddedSignInFlowHandleRequestPayload, request: EmbeddedFlowExecuteRequestConfig, ): Promise => { - return await signIn(payload, request); + if (!signIn) { + throw new AsgardeoRuntimeError( + '`signIn` function is not available.', + 'SignIn-handleOnSubmit-RuntimeError-001', + 'nextjs', + ); + } + + return (await signIn(payload, request)) as Promise; }; return ( diff --git a/packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx b/packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx index 17dba8e9..6ea895e6 100644 --- a/packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx +++ b/packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx @@ -19,6 +19,7 @@ 'use client'; import { + AsgardeoRuntimeError, EmbeddedFlowExecuteRequestPayload, EmbeddedFlowExecuteResponse, EmbeddedFlowResponseType, @@ -72,18 +73,35 @@ const SignUp: FC = ({className, size = 'medium', variant = 'outline const handleInitialize = async ( payload?: EmbeddedFlowExecuteRequestPayload, ): Promise => { - return await signUp( + if (!signUp) { + throw new AsgardeoRuntimeError( + '`signUp` function is not available.', + 'SignUp-handleInitialize-RuntimeError-001', + 'nextjs', + ); + } + + return (await signUp( payload || { flowType: EmbeddedFlowType.Registration, }, - ); + )) as unknown as Promise; }; /** * Handle sign-up steps. */ - const handleOnSubmit = async (payload: EmbeddedFlowExecuteRequestPayload): Promise => - await signUp(payload); + const handleOnSubmit = async (payload: EmbeddedFlowExecuteRequestPayload): Promise => { + if (!signUp) { + throw new AsgardeoRuntimeError( + '`signUp` function is not available.', + 'SignUp-handleOnSubmit-RuntimeError-001', + 'nextjs', + ); + } + + return (await signUp(payload)) as unknown as Promise; + }; return ( = createContext Promise.resolve({} as any), + signOut: () => Promise.resolve({} as any), + signUp: () => Promise.resolve({} as any), user: null, }); diff --git a/packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx b/packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx index b6ff0c37..4b52db7d 100644 --- a/packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx +++ b/packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx @@ -31,6 +31,7 @@ import { BrandingPreference, TokenResponse, CreateOrganizationPayload, + AsgardeoRuntimeError, } from '@asgardeo/node'; import { I18nProvider, @@ -191,6 +192,14 @@ const AsgardeoClientProvider: FC> payload: EmbeddedSignInFlowHandleRequestPayload, request: EmbeddedFlowExecuteRequestConfig, ) => { + if (!signIn) { + throw new AsgardeoRuntimeError( + '`signIn` function is not available.', + 'AsgardeoClientProvider-handleSignIn-RuntimeError-001', + 'nextjs', + ); + } + try { const result = await signIn(payload, request); @@ -222,6 +231,14 @@ const AsgardeoClientProvider: FC> payload: EmbeddedFlowExecuteRequestPayload, request: EmbeddedFlowExecuteRequestConfig, ) => { + if (!signUp) { + throw new AsgardeoRuntimeError( + '`signUp` function is not available.', + 'AsgardeoClientProvider-handleSignUp-RuntimeError-001', + 'nextjs', + ); + } + try { const result = await signUp(payload, request); diff --git a/packages/react/src/AsgardeoReactClient.ts b/packages/react/src/AsgardeoReactClient.ts index ee584640..0901ad30 100644 --- a/packages/react/src/AsgardeoReactClient.ts +++ b/packages/react/src/AsgardeoReactClient.ts @@ -49,6 +49,7 @@ import { TokenExchangeRequestConfig, Platform, isEmpty, + EmbeddedSignInFlowResponseV2, } from '@asgardeo/browser'; import AuthAPI from './__temp__/api'; import getMeOrganizations from './api/getMeOrganizations'; @@ -328,7 +329,7 @@ class AsgardeoReactClient e sessionId?: string, onSignInSuccess?: (afterSignInUrl: string) => void, ): Promise; - override async signIn(...args: any[]): Promise { + override async signIn(...args: any[]): Promise { return this.withLoading(async () => { const arg1 = args[0]; const arg2 = args[1]; diff --git a/packages/react/src/components/adapters/CheckboxInput.tsx b/packages/react/src/components/adapters/CheckboxInput.tsx index c7ea51a9..c368d928 100644 --- a/packages/react/src/components/adapters/CheckboxInput.tsx +++ b/packages/react/src/components/adapters/CheckboxInput.tsx @@ -32,18 +32,18 @@ const CheckboxInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string | boolean = (formValues[fieldName] as string) || false; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return createField({ type: FieldType.Checkbox, name: fieldName, - label: config['label'] || '', - placeholder: config['placeholder'] || '', - required: config['required'] || false, - value, + label: (config['label'] as string) || '', + placeholder: (config['placeholder'] as string) || '', + required: (config['required'] as boolean) || false, + value: value as string, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), className: inputClassName, diff --git a/packages/react/src/components/adapters/DateInput.tsx b/packages/react/src/components/adapters/DateInput.tsx index 26550dbc..9f6dc1d8 100644 --- a/packages/react/src/components/adapters/DateInput.tsx +++ b/packages/react/src/components/adapters/DateInput.tsx @@ -32,17 +32,17 @@ const DateInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string = formValues[fieldName] || ''; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return createField({ type: FieldType.Date, name: fieldName, - label: config['label'] || '', - placeholder: config['placeholder'] || '', - required: config['required'] || false, + label: (config['label'] as string) || '', + placeholder: (config['placeholder'] as string) || '', + required: (config['required'] as boolean) || false, value, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), diff --git a/packages/react/src/components/adapters/DividerComponent.tsx b/packages/react/src/components/adapters/DividerComponent.tsx index 60b8afbb..86101bd9 100644 --- a/packages/react/src/components/adapters/DividerComponent.tsx +++ b/packages/react/src/components/adapters/DividerComponent.tsx @@ -26,9 +26,9 @@ import useTheme from '../../contexts/Theme/useTheme'; */ const DividerComponent: FC = ({component}) => { const {theme} = useTheme(); - const config = component.config || {}; - const text = config['text'] || ''; - const variant = component.variant?.toLowerCase() || 'horizontal'; + const config: Record = component.config || {}; + const text = (config['text'] as string) || ''; + const variant = (component.variant?.toLowerCase() as string) || 'horizontal'; return ( = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string = formValues[fieldName] || ''; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return createField({ type: FieldType.Email, name: fieldName, - label: config['label'] || 'Email', - placeholder: config['placeholder'] || 'Enter your email', - required: config['required'] || false, + label: (config['label'] as string) || 'Email', + placeholder: (config['placeholder'] as string) || 'Enter your email', + required: (config['required'] as boolean) || false, value, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), diff --git a/packages/react/src/components/adapters/ImageComponent.tsx b/packages/react/src/components/adapters/ImageComponent.tsx index 7df86377..b1d2cc89 100644 --- a/packages/react/src/components/adapters/ImageComponent.tsx +++ b/packages/react/src/components/adapters/ImageComponent.tsx @@ -25,10 +25,10 @@ import useTheme from '../../contexts/Theme/useTheme'; */ const ImageComponent: FC = ({component}) => { const {theme} = useTheme(); - const config = component.config || {}; - const src = config['src'] || ''; - const alt = config['alt'] || config['label'] || 'Image'; - const variant = component.variant?.toLowerCase() || 'image_block'; + const config: Record = component.config || {}; + const src = (config['src'] as string) || ''; + const alt = (config['alt'] as string) || (config['label'] as string) || 'Image'; + const variant = (component.variant?.toLowerCase() as string) || 'image_block'; const imageStyle: React.CSSProperties = { maxWidth: '100%', diff --git a/packages/react/src/components/adapters/NumberInput.tsx b/packages/react/src/components/adapters/NumberInput.tsx index 9bb3cced..a1340fbd 100644 --- a/packages/react/src/components/adapters/NumberInput.tsx +++ b/packages/react/src/components/adapters/NumberInput.tsx @@ -32,17 +32,17 @@ const NumberInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string = formValues[fieldName] || ''; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return createField({ type: FieldType.Number, name: fieldName, - label: config['label'] || '', - placeholder: config['placeholder'] || '', - required: config['required'] || false, + label: (config['label'] as string) || '', + placeholder: (config['placeholder'] as string) || '', + required: (config['required'] as boolean) || false, value, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), diff --git a/packages/react/src/components/adapters/PasswordInput.tsx b/packages/react/src/components/adapters/PasswordInput.tsx index 2d154f25..af4efa3c 100644 --- a/packages/react/src/components/adapters/PasswordInput.tsx +++ b/packages/react/src/components/adapters/PasswordInput.tsx @@ -32,13 +32,20 @@ const PasswordInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string = formValues[fieldName] || ''; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; // Extract validation rules from the component config if available - const validations = config['validations'] || []; + const validations: { + conditions?: {key: string; value: string}[]; + name: string; + }[] = + (config['validations'] as { + conditions?: {key: string; value: string}[]; + name: string; + }[]) || []; const validationHints: string[] = []; validations.forEach((validation: any) => { @@ -76,9 +83,9 @@ const PasswordInput: FC = ({ return createField({ type: FieldType.Password, name: fieldName, - label: config['label'] || 'Password', - placeholder: config['placeholder'] || 'Enter your password', - required: config['required'] || false, + label: (config['label'] as string) || 'Password', + placeholder: (config['placeholder'] as string) || 'Enter your password', + required: (config['required'] as boolean) || false, value, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), diff --git a/packages/react/src/components/adapters/SocialButton.tsx b/packages/react/src/components/adapters/SocialButton.tsx index ec57ed46..037cabd4 100644 --- a/packages/react/src/components/adapters/SocialButton.tsx +++ b/packages/react/src/components/adapters/SocialButton.tsx @@ -31,8 +31,8 @@ const SocialButton: FC = ({ size = 'medium', onSubmit, }) => { - const config = component.config || {}; - const buttonText: string = config['text'] || config['label'] || 'Continue with Social'; + const config: Record = component.config || {}; + const buttonText: string = (config['text'] as string) || (config['label'] as string) || 'Continue with Social'; const handleClick = (): void => { if (onSubmit) { diff --git a/packages/react/src/components/adapters/SubmitButton.tsx b/packages/react/src/components/adapters/SubmitButton.tsx index b6643b31..c8416fdc 100644 --- a/packages/react/src/components/adapters/SubmitButton.tsx +++ b/packages/react/src/components/adapters/SubmitButton.tsx @@ -33,10 +33,10 @@ const ButtonComponent: FC = ({ onSubmit, size = 'medium', }) => { - const config = component.config || {}; - const buttonText = config['text'] || config['label'] || 'Continue'; - const buttonType = config['type'] || 'submit'; - const componentVariant = component.variant?.toUpperCase() || 'PRIMARY'; + const config: Record = component.config || {}; + const buttonText: string = (config['text'] as string) || (config['label'] as string) || 'Continue'; + const buttonType: string = (config['type'] as string) || 'submit'; + const componentVariant: string = component.variant?.toUpperCase() || 'PRIMARY'; // Map component variants to Button primitive props const getButtonProps = () => { diff --git a/packages/react/src/components/adapters/TelephoneInput.tsx b/packages/react/src/components/adapters/TelephoneInput.tsx index 300059f4..f17734ef 100644 --- a/packages/react/src/components/adapters/TelephoneInput.tsx +++ b/packages/react/src/components/adapters/TelephoneInput.tsx @@ -31,24 +31,24 @@ const TelephoneInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; - const value = formValues[fieldName] || ''; - const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; + const value: string = formValues[fieldName] || ''; + const error: string | undefined = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return ( onInputChange(fieldName, e.target.value)} className={inputClassName} - helperText={config['hint'] || ''} + helperText={config['hint'] as string || ''} /> ); }; diff --git a/packages/react/src/components/adapters/TextInput.tsx b/packages/react/src/components/adapters/TextInput.tsx index 7c6d0969..dd49bcfc 100644 --- a/packages/react/src/components/adapters/TextInput.tsx +++ b/packages/react/src/components/adapters/TextInput.tsx @@ -32,17 +32,17 @@ const TextInput: FC = ({ onInputChange, inputClassName, }) => { - const config = component.config || {}; - const fieldName = config['identifier'] || config['name'] || component.id; + const config: Record = component.config || {}; + const fieldName: string = (config['identifier'] as string) || (config['name'] as string) || component.id; const value = formValues[fieldName] || ''; const error = touchedFields[fieldName] ? formErrors[fieldName] : undefined; return createField({ type: FieldType.Text, name: fieldName, - label: config['label'] || '', - placeholder: config['placeholder'] || '', - required: config['required'] || false, + label: config['label'] as string || '', + placeholder: config['placeholder'] as string || '', + required: config['required'] as boolean || false, value, error, onChange: (newValue: string) => onInputChange(fieldName, newValue), diff --git a/packages/react/src/components/adapters/Typography.tsx b/packages/react/src/components/adapters/Typography.tsx index 4752dde4..777bd6e4 100644 --- a/packages/react/src/components/adapters/Typography.tsx +++ b/packages/react/src/components/adapters/Typography.tsx @@ -26,9 +26,9 @@ import useTheme from '../../contexts/Theme/useTheme'; */ const TypographyComponent: FC = ({component}) => { const {theme} = useTheme(); - const config = component.config || {}; - const text = config['text'] || config['content'] || ''; - const variant = component.variant?.toLowerCase() || 'body1'; + const config: Record = component.config || {}; + const text: string = (config['text'] as string) || (config['content'] as string) || ''; + const variant: string = component.variant?.toLowerCase() || 'body1'; // Map component variants to Typography variants let typographyVariant: any = 'body1'; diff --git a/packages/react/src/components/presentation/SignIn/SignIn.tsx b/packages/react/src/components/presentation/SignIn/SignIn.tsx index dfc37218..ca5c2ee1 100644 --- a/packages/react/src/components/presentation/SignIn/SignIn.tsx +++ b/packages/react/src/components/presentation/SignIn/SignIn.tsx @@ -70,7 +70,7 @@ const SignIn: FC = ({className, size = 'medium', children, ...rest} * Initialize the authentication flow. */ const handleInitialize = async (): Promise => { - return await signIn({response_mode: 'direct'}); + return await signIn({response_mode: 'direct'}) as EmbeddedSignInFlowInitiateResponse; }; /** @@ -80,7 +80,7 @@ const SignIn: FC = ({className, size = 'medium', children, ...rest} payload: EmbeddedSignInFlowHandleRequestPayload, request: Request, ): Promise => { - return await signIn(payload, request); + return await signIn(payload, request) as EmbeddedSignInFlowHandleResponse; }; /** diff --git a/packages/react/src/components/presentation/SignIn/component-driven/BaseSignIn.tsx b/packages/react/src/components/presentation/SignIn/component-driven/BaseSignIn.tsx index 83d5bca7..2502877d 100644 --- a/packages/react/src/components/presentation/SignIn/component-driven/BaseSignIn.tsx +++ b/packages/react/src/components/presentation/SignIn/component-driven/BaseSignIn.tsx @@ -266,7 +266,7 @@ const BaseSignInContent: FC = ({ const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); - const isLoading = externalIsLoading || isSubmitting; + const isLoading: boolean = externalIsLoading || isSubmitting; /** * Extract form fields from flow components @@ -278,10 +278,10 @@ const BaseSignInContent: FC = ({ const processComponents = (comps: EmbeddedFlowComponent[]) => { comps.forEach(component => { if (component.type === 'INPUT' && component.config) { - const identifier = component.config['identifier'] || component.id; + const identifier: string = (component.config['identifier'] as string) || component.id; fields.push({ name: identifier, - required: component.config['required'] || false, + required: component.config['required'] as unknown as boolean || false, initialValue: '', validator: (value: string) => { if (component.config['required'] && (!value || value.trim() === '')) { @@ -363,7 +363,7 @@ const BaseSignInContent: FC = ({ if (component.config['actionId']) { payload = { ...payload, - actionId: component.config['actionId'], + actionId: component.config['actionId'] as string, }; } else { payload = { diff --git a/packages/react/src/components/presentation/SignIn/component-driven/SignIn.tsx b/packages/react/src/components/presentation/SignIn/component-driven/SignIn.tsx index 1ca66989..3e64fcc9 100644 --- a/packages/react/src/components/presentation/SignIn/component-driven/SignIn.tsx +++ b/packages/react/src/components/presentation/SignIn/component-driven/SignIn.tsx @@ -206,7 +206,7 @@ const SignIn: FC = ({className, size = 'medium', onSuccess, onError const response: EmbeddedSignInFlowResponseV2 = await signIn({ applicationId: applicationId || applicationIdFromUrl, flowType: EmbeddedFlowType.Authentication, - }); + }) as EmbeddedSignInFlowResponseV2; const {flowId, components} = normalizeFlowResponse(response, t); @@ -241,10 +241,10 @@ const SignIn: FC = ({className, size = 'medium', onSuccess, onError setIsSubmitting(true); setFlowError(null); - const response = await signIn({ + const response: EmbeddedSignInFlowResponseV2 = await signIn({ flowId: currentFlowId, ...payload, - }); + }) as EmbeddedSignInFlowResponseV2; const {flowId, components} = normalizeFlowResponse(response, t); diff --git a/packages/react/src/components/presentation/SignIn/component-driven/SignInOptionFactory.tsx b/packages/react/src/components/presentation/SignIn/component-driven/SignInOptionFactory.tsx index 092d8c8c..ad24164b 100644 --- a/packages/react/src/components/presentation/SignIn/component-driven/SignInOptionFactory.tsx +++ b/packages/react/src/components/presentation/SignIn/component-driven/SignInOptionFactory.tsx @@ -79,22 +79,22 @@ const createSignInComponentFromFlow = ( variant?: any; } = {}, ): ReactElement | null => { - const key = options.key || component.id; + const key: string | number = options.key || component.id; switch (component.type) { case EmbeddedFlowComponentType.Input: { - const identifier = component.config['identifier'] || component.id; - const value = formValues[identifier] || ''; - const isTouched = touchedFields[identifier] || false; - const error = isTouched ? formErrors[identifier] : undefined; - const fieldType = getFieldType(component.variant || 'TEXT'); + const identifier: string = component.config['identifier'] as string || component.id; + const value: string = formValues[identifier] || ''; + const isTouched: boolean = touchedFields[identifier] || false; + const error: string = isTouched ? formErrors[identifier] : undefined; + const fieldType: string = getFieldType(component.variant || 'TEXT'); const field = createField({ - type: fieldType, + type: fieldType as FieldType, name: identifier, - label: component.config['label'] || '', - placeholder: component.config['placeholder'] || '', - required: component.config['required'] || false, + label: component.config['label'] as string || '', + placeholder: component.config['placeholder'] as string || '', + required: component.config['required'] as unknown as boolean || false, value, error, onChange: (newValue: string) => onInputChange(identifier, newValue), @@ -118,7 +118,7 @@ const createSignInComponentFromFlow = ( }; // Render branded social login buttons for known action IDs - const actionId: string = component.config['actionId']; + const actionId: string = component.config['actionId'] as string; if (actionId === 'google_auth') { return ; @@ -144,7 +144,7 @@ const createSignInComponentFromFlow = ( variant={component.variant?.toLowerCase() === 'primary' ? 'solid' : 'outline'} color={component.variant?.toLowerCase() === 'primary' ? 'primary' : 'secondary'} > - {component.config['text'] || 'Submit'} + {component.config['text'] as string || 'Submit'} ); } @@ -153,7 +153,7 @@ const createSignInComponentFromFlow = ( const variant = getTypographyVariant(component.variant || 'H3'); return ( - {component.config['text'] || ''} + {component.config['text'] as string || ''} ); } diff --git a/packages/react/src/components/presentation/SignIn/component-driven/transformer.ts b/packages/react/src/components/presentation/SignIn/component-driven/transformer.ts index 647c8eec..ca9b8acd 100644 --- a/packages/react/src/components/presentation/SignIn/component-driven/transformer.ts +++ b/packages/react/src/components/presentation/SignIn/component-driven/transformer.ts @@ -93,7 +93,7 @@ const convertSimpleInputToComponent = ( type: input.type === 'string' ? 'text' : input.type, label, placeholder, - required: input.required, + required: input.required as boolean, identifier: input.name, hint: '', }, diff --git a/packages/react/src/components/presentation/SignUp/SignUp.tsx b/packages/react/src/components/presentation/SignUp/SignUp.tsx index 69642e41..6cab4b59 100644 --- a/packages/react/src/components/presentation/SignUp/SignUp.tsx +++ b/packages/react/src/components/presentation/SignUp/SignUp.tsx @@ -80,13 +80,13 @@ const SignUp: FC = ({ payload || { flowType: EmbeddedFlowType.Registration, }, - ); + ) as EmbeddedFlowExecuteResponse; /** * Handle sign-up steps. */ const handleOnSubmit = async (payload: EmbeddedFlowExecuteRequestPayload): Promise => - await signUp(payload); + await signUp(payload) as EmbeddedFlowExecuteResponse; /** * Handle successful sign-up and redirect. diff --git a/packages/react/src/components/presentation/SignUp/SignUpOptionFactory.tsx b/packages/react/src/components/presentation/SignUp/SignUpOptionFactory.tsx index 691d62d3..a92fc528 100644 --- a/packages/react/src/components/presentation/SignUp/SignUpOptionFactory.tsx +++ b/packages/react/src/components/presentation/SignUp/SignUpOptionFactory.tsx @@ -114,8 +114,8 @@ export const createSignUpComponent = ({component, onSubmit, ...rest}: BaseSignUp case EmbeddedFlowComponentType.Input: // Determine input type based on variant or config - const inputVariant = component.variant?.toUpperCase(); - const inputType = component.config['type']?.toLowerCase(); + const inputVariant: string = component.variant?.toUpperCase(); + const inputType: string = (component.config['type'] as string)?.toLowerCase(); if (inputVariant === 'EMAIL' || inputType === 'email') { return ; @@ -145,7 +145,7 @@ export const createSignUpComponent = ({component, onSubmit, ...rest}: BaseSignUp case EmbeddedFlowComponentType.Button: { const buttonVariant: string | undefined = component.variant?.toUpperCase(); - const buttonText: string = component.config['text'] || component.config['label'] || ''; + const buttonText: string = component.config['text'] as string || component.config['label'] as string || ''; // TODO: The connection type should come as metadata. if (buttonVariant === 'SOCIAL') { diff --git a/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts b/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts index 2907b3ab..f705f3cc 100644 --- a/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts +++ b/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts @@ -18,6 +18,8 @@ import {Context, createContext} from 'react'; import { + EmbeddedFlowExecuteResponse, + EmbeddedSignInFlowResponseV2, HttpRequestConfig, HttpResponse, IdToken, @@ -25,6 +27,7 @@ import { SignInOptions, TokenExchangeRequestConfig, TokenResponse, + User, } from '@asgardeo/browser'; import AsgardeoReactClient from '../../AsgardeoReactClient'; import {AsgardeoReactConfig} from '../../models/config'; @@ -53,7 +56,11 @@ export type AsgardeoContextProps = { * @remark This is the programmatic version of the `SignInButton` component. * TODO: Fix the types. */ - signIn: any; + signIn: (...args: any) => Promise; + /** + * Silent sign-in function to re-authenticate the user without user interaction. + * @remark This is the programmatic version of the `SilentSignIn` component. + */ signInSilently: AsgardeoReactClient['signInSilently']; /** * Sign-out function to terminate the authentication session. @@ -64,9 +71,8 @@ export type AsgardeoContextProps = { /** * Sign-up function to initiate the registration process. * @remark This is the programmatic version of the `SignUpButton` component. - * FIXME: Fix the types. */ - signUp: any; + signUp: (...args: any[]) => Promise; user: any; organization: Organization; /** @@ -150,10 +156,10 @@ const AsgardeoContext: Context = createContext Promise.resolve({} as any), + signInSilently: () => Promise.resolve({} as any), + signOut: () => Promise.resolve({} as any), + signUp: () => Promise.resolve({} as any), user: null, http: { request: () => null,