Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

import AsgardeoAPIError from '../../errors/AsgardeoAPIError';
import {EmbeddedFlowType} from '../../models/embedded-flow';
import {EmbeddedFlowExecuteRequestConfig as EmbeddedFlowExecuteRequestConfigV2} from '../../models/v2/embedded-flow-v2';
import {
EmbeddedFlowExecuteRequestConfig as EmbeddedFlowExecuteRequestConfigV2,
FlowExecuteError,
} from '../../models/v2/embedded-flow-v2';

/**
* Response from the user onboarding flow execution.
Expand All @@ -45,9 +48,9 @@ export interface EmbeddedUserOnboardingFlowResponse {
executionId: string;

/**
* Reason for failure if flowStatus is ERROR.
* Structured error detail present when flowStatus is ERROR.
*/
failureReason?: string;
error?: FlowExecuteError;

/**
* Current status of the flow.
Expand Down
2 changes: 2 additions & 0 deletions packages/javascript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export {
ConsentDecisions as ConsentDecisionsV2,
ConsentPurposeData as ConsentPurposeDataV2,
ConsentPromptData as ConsentPromptDataV2,
FlowExecuteError,
} from './models/v2/embedded-flow-v2';
export {
EmbeddedSignInFlowStatus as EmbeddedSignInFlowStatusV2,
Expand All @@ -116,6 +117,7 @@ export {
export {
EmbeddedRecoveryFlowStatus as EmbeddedRecoveryFlowStatusV2,
EmbeddedRecoveryFlowType as EmbeddedRecoveryFlowTypeV2,
ExtendedEmbeddedRecoveryFlowResponse as ExtendedEmbeddedRecoveryFlowResponseV2,
EmbeddedRecoveryFlowResponse as EmbeddedRecoveryFlowResponseV2,
EmbeddedRecoveryFlowInitiateRequest as EmbeddedRecoveryFlowInitiateRequestV2,
EmbeddedRecoveryFlowRequest as EmbeddedRecoveryFlowRequestV2,
Expand Down
14 changes: 14 additions & 0 deletions packages/javascript/src/models/v2/embedded-flow-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,20 @@ export interface ConsentPromptData {
purposes: ConsentPurposeData[];
}

/**
* Structured error detail returned by the flow/execute endpoint when flowStatus is ERROR.
*
* @experimental Part of the new Asgardeo API
*/
export interface FlowExecuteError {
/** Machine-readable error code (e.g. "FEE-60005"). */
code: string;
/** Localizable description with translation key and English default. */
description: {default: string; key: string};
/** Localizable short message with translation key and English default. */
message: {default: string; key: string};
}

/**
* Extended request configuration for Asgardeo V2 embedded flow operations.
*
Expand Down
42 changes: 20 additions & 22 deletions packages/javascript/src/models/v2/embedded-recovery-flow-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import {EmbeddedFlowType} from '../embedded-flow';
import {EmbeddedFlowResponseData as EmbeddedFlowResponseDataV2, FlowExecuteError} from './embedded-flow-v2';

/**
* Status enumeration for the embedded recovery flow operations.
Expand Down Expand Up @@ -59,47 +60,44 @@ export enum EmbeddedRecoveryFlowType {
View = 'VIEW',
}

/**
* Extended response structure for the embedded recovery flow.
* @remarks This response is only done from the SDK level.
* @experimental
*/
export interface ExtendedEmbeddedRecoveryFlowResponse {
/**
* The URL to redirect the user after completing the recovery flow.
*/
redirectUrl?: string;
}

/**
* Response structure for the embedded recovery flow.
*
* @experimental Part of the new Asgardeo API
*/
export interface EmbeddedRecoveryFlowResponse {
export interface EmbeddedRecoveryFlowResponse extends ExtendedEmbeddedRecoveryFlowResponse {
/**
* Per-step challenge token for replay protection.
* Must be included in the next request to continue this flow.
*/
challengeToken?: string;

/**
* Flow data containing UI components for the current step.
* Core response data containing UI components and flow metadata.
*/
data: {
/**
* Additional data from the flow step.
*/
additionalData?: Record<string, any>;

/**
* UI components to render for the current step.
*/
components?: any[];

/**
* Redirect URL if type is REDIRECTION.
*/
redirectURL?: string;
};
data: EmbeddedFlowResponseDataV2;

/**
* Unique identifier for this recovery flow execution.
*/
executionId: string;

/**
* Optional reason for failure when flowStatus is ERROR.
* Structured error detail present when flowStatus is ERROR.
*/
failureReason?: string;
error?: FlowExecuteError;

/**
* Current status of the recovery flow.
Expand Down Expand Up @@ -151,9 +149,9 @@ export interface EmbeddedRecoveryFlowErrorResponse {
executionId: string;

/**
* Human-readable explanation of why the recovery operation failed.
* Structured error detail describing why the recovery operation failed.
*/
failureReason: string;
error: FlowExecuteError;

/**
* Status of the recovery flow — always ERROR for this interface.
Expand Down
7 changes: 3 additions & 4 deletions packages/javascript/src/models/v2/embedded-signin-flow-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/

import {EmbeddedFlowResponseData as EmbeddedFlowResponseDataV2} from './embedded-flow-v2';
import {EmbeddedFlowResponseData as EmbeddedFlowResponseDataV2, FlowExecuteError} from './embedded-flow-v2';
import {
EmbeddedFlowResponseType as EmbeddedFlowResponseTypeV1,
EmbeddedFlowType as EmbeddedFlowTypeV1,
Expand Down Expand Up @@ -209,10 +209,9 @@ export interface EmbeddedSignInFlowResponse extends ExtendedEmbeddedSignInFlowRe
executionId: string;

/**
* Optional reason for flow failure in case of an error.
* Provides additional context when flowStatus is set to ERROR.
* Structured error detail present when flowStatus is ERROR.
*/
failureReason?: string;
error?: FlowExecuteError;

/**
* Current status of the sign-in flow.
Expand Down
17 changes: 11 additions & 6 deletions packages/javascript/src/models/v2/embedded-signup-flow-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
EmbeddedFlowResponseType as EmbeddedFlowResponseTypeV1,
EmbeddedFlowType as EmbeddedFlowTypeV1,
} from '../embedded-flow';
import {EmbeddedFlowResponseData as EmbeddedFlowResponseDataV2, FlowExecuteError} from './embedded-flow-v2';

/**
* Status enumeration for Asgardeo embedded sign-up flow operations.
Expand Down Expand Up @@ -148,12 +149,13 @@ export interface EmbeddedSignUpFlowResponse extends ExtendedEmbeddedSignUpFlowRe
challengeToken?: string;

/**
* Flow data containing form inputs and available actions.
* Core response data containing UI components and flow metadata.
* This is transformed to component-driven format by the React transformer.
*/
data: {
data: EmbeddedFlowResponseDataV2 & {
/**
* Available actions the user can take (e.g., form submission, social sign-up).
* @deprecated Use data.meta.components for new implementations
*/
actions?: {
id: string;
Expand All @@ -162,6 +164,7 @@ export interface EmbeddedSignUpFlowResponse extends ExtendedEmbeddedSignUpFlowRe

/**
* Input fields required for the current step of the sign-up flow.
* @deprecated Use data.meta.components for new implementations
*/
inputs?: {
name: string;
Expand All @@ -176,10 +179,9 @@ export interface EmbeddedSignUpFlowResponse extends ExtendedEmbeddedSignUpFlowRe
executionId: string;

/**
* Optional reason for flow failure in case of an error.
* Provides additional context when flowStatus is set to ERROR.
* Structured error detail present when flowStatus is ERROR.
*/
failureReason?: string;
error?: FlowExecuteError;

/**
* Current status of the sign-up flow.
Expand Down Expand Up @@ -284,7 +286,10 @@ export interface EmbeddedSignUpFlowErrorResponse {
*/
executionId: string;

failureReason: string;
/**
* Structured error detail describing why the sign-up operation failed.
*/
error: FlowExecuteError;

/**
* Status of the sign-up flow, which will be `EmbeddedSignUpFlowStatus.Error`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export interface AcceptInviteFlowResponse {
};
redirectURL?: string;
};
error?: {code: string; description?: {default: string; key: string}; message?: {default: string; key: string}};
executionId: string;
failureReason?: string;
flowStatus: 'INCOMPLETE' | 'COMPLETE' | 'ERROR';
type?: 'VIEW' | 'REDIRECTION';
}
Expand Down Expand Up @@ -329,8 +329,7 @@ const BaseAcceptInvite: FC<BaseAcceptInviteProps> = ({
const handleError: any = useCallback(
(error: any) => {
// Extract error message from response failureReason or use extractErrorMessage
const errorMessage: string =
error?.failureReason || extractErrorMessage(error, t, 'components.acceptInvite.errors.generic');
const errorMessage: string = extractErrorMessage(error, t, 'components.acceptInvite.errors.generic');

// Set the API error state
setApiError(error instanceof Error ? error : new Error(errorMessage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ export interface InviteUserFlowResponse {
components?: any[];
};
};
error?: {code: string; description?: {default: string; key: string}; message?: {default: string; key: string}};
executionId: string;
failureReason?: string;
flowStatus: 'INCOMPLETE' | 'COMPLETE' | 'ERROR';
type?: 'VIEW' | 'REDIRECTION';
}
Expand Down Expand Up @@ -321,8 +321,7 @@ const BaseInviteUser: FC<BaseInviteUserProps> = ({
const handleError: any = useCallback(
(error: any) => {
// Extract error message from response failureReason or use extractErrorMessage
const errorMessage: string =
error?.failureReason || extractErrorMessage(error, t, 'components.inviteUser.errors.generic');
const errorMessage: string = extractErrorMessage(error, t, 'components.inviteUser.errors.generic');

// Set the API error state
setApiError(error instanceof Error ? error : new Error(errorMessage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
*/

import {
EmbeddedFlowExecuteRequestPayload,
EmbeddedFlowExecuteResponse,
EmbeddedFlowStatus,
EmbeddedRecoveryFlowRequestV2,
EmbeddedRecoveryFlowResponseV2,
EmbeddedRecoveryFlowStatusV2,
EmbeddedFlowComponentTypeV2 as EmbeddedFlowComponentType,
withVendorCSSClassPrefix,
Preferences,
Expand Down Expand Up @@ -83,11 +83,11 @@ export interface BaseRecoveryProps {
inputClassName?: string;
isInitialized?: boolean;
messageClassName?: string;
onComplete?: (response: EmbeddedFlowExecuteResponse) => void;
onComplete?: (response: EmbeddedRecoveryFlowResponseV2) => void;
onError?: (error: Error) => void;
onFlowChange?: (response: EmbeddedFlowExecuteResponse) => void;
onInitialize?: (payload?: EmbeddedFlowExecuteRequestPayload) => Promise<EmbeddedFlowExecuteResponse>;
onSubmit?: (payload: EmbeddedFlowExecuteRequestPayload) => Promise<EmbeddedFlowExecuteResponse>;
onFlowChange?: (response: EmbeddedRecoveryFlowResponseV2) => void;
onInitialize?: (payload?: EmbeddedRecoveryFlowRequestV2) => Promise<EmbeddedRecoveryFlowResponseV2>;
onSubmit?: (payload: EmbeddedRecoveryFlowRequestV2) => Promise<EmbeddedRecoveryFlowResponseV2>;
/**
* Component-level preferences to override global i18n and theme settings.
*/
Expand Down Expand Up @@ -132,15 +132,15 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({

const [isLoading, setIsLoading] = useState(false);
const [isFlowInitialized, setIsFlowInitialized] = useState(false);
const [currentFlow, setCurrentFlow] = useState<EmbeddedFlowExecuteResponse | null>(null);
const [currentFlow, setCurrentFlow] = useState<EmbeddedRecoveryFlowResponseV2 | null>(null);
const [apiError, setApiError] = useState<Error | null>(null);

const initializationAttemptedRef: any = useRef(false);
const challengeTokenRef: any = useRef<string | null>(null);

const handleError: any = useCallback(
(error: any) => {
const errorMessage: string = error?.failureReason || extractErrorMessage(error, t);
const errorMessage: string = extractErrorMessage(error, t);
setApiError(error instanceof Error ? error : new Error(errorMessage));
clearMessages();
addMessage({message: errorMessage, type: 'error'});
Expand All @@ -149,8 +149,8 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
);

const normalizeFlowResponseLocal: any = useCallback(
(response: EmbeddedFlowExecuteResponse): EmbeddedFlowExecuteResponse => {
if (response?.data?.components && Array.isArray(response.data.components)) {
(response: EmbeddedRecoveryFlowResponseV2): EmbeddedRecoveryFlowResponseV2 => {
if ((response?.data as any)?.components && Array.isArray((response.data as any).components)) {
return response;
}

Expand Down Expand Up @@ -215,7 +215,7 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
[t],
);

const formFields: any = currentFlow?.data?.components ? extractFormFields(currentFlow.data.components) : [];
const formFields: any = (currentFlow?.data as any)?.components ? extractFormFields((currentFlow.data as any).components) : [];

const form: any = useForm<Record<string, string>>({
fields: formFields,
Expand All @@ -238,8 +238,8 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
} = form;

const setupFormFields: any = useCallback(
(flowResponse: EmbeddedFlowExecuteResponse) => {
const fields: any = extractFormFields(flowResponse.data?.components || []);
(flowResponse: EmbeddedRecoveryFlowResponseV2) => {
const fields: any = extractFormFields((flowResponse.data as any)?.components || []);
const initialValues: Record<string, string> = {};
fields.forEach((field: any) => {
initialValues[field.name] = field.initialValue || '';
Expand Down Expand Up @@ -281,7 +281,7 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
});
}

const payload: EmbeddedFlowExecuteRequestPayload = {
const payload: EmbeddedRecoveryFlowRequestV2 = {
...((currentFlow as any).executionId && {executionId: (currentFlow as any).executionId}),
flowType: (currentFlow as any).flowType || 'RECOVERY',
...(component.id && {action: component.id}),
Expand All @@ -298,12 +298,12 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
challengeTokenRef.current = response.challengeToken ?? null;
}

if (response.flowStatus === EmbeddedFlowStatus.Complete) {
if (response.flowStatus === EmbeddedRecoveryFlowStatusV2.Complete) {
onComplete?.(response);
return;
}

if (response.flowStatus === EmbeddedFlowStatus.Incomplete) {
if (response.flowStatus === EmbeddedRecoveryFlowStatusV2.Incomplete) {
setCurrentFlow(response);
setupFormFields(response);
}
Expand Down Expand Up @@ -407,12 +407,12 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
setIsFlowInitialized(true);
onFlowChange?.(response);

if (response.flowStatus === EmbeddedFlowStatus.Complete) {
if (response.flowStatus === EmbeddedRecoveryFlowStatusV2.Complete) {
onComplete?.(response);
return;
}

if (response.flowStatus === EmbeddedFlowStatus.Incomplete) {
if (response.flowStatus === EmbeddedRecoveryFlowStatusV2.Incomplete) {
setupFormFields(response);
}
} catch (err) {
Expand Down Expand Up @@ -488,7 +488,7 @@ const BaseRecoveryContent: FC<BaseRecoveryProps> = ({
);
}

const componentsToRender: any = currentFlow.data?.components || [];
const componentsToRender: any = (currentFlow.data as any)?.components || [];
const {title, subtitle, componentsWithoutHeadings} = getAuthComponentHeadings(
componentsToRender,
flowTitle,
Expand Down
Loading
Loading