UNPKG

pagamio-frontend-commons-lib

Version:

Pagamio library for Frontend reusable components like the form engine and table container

264 lines (263 loc) 8.75 kB
import { jwtDecode } from 'jwt-decode'; /** * Transforms authentication responses from the Events App API format into a standardized AuthResponse. * This transformer handles responses that include a single token and role-based user information. * * Expected API response format: * ```typescript * { * token: string; * firstName: string; * lastName: string; * username: string; * roles: string[] | null; * roleName: string; * roleDesc: string; * vendorId: number; * promoterId: number | null; * company: string; * } * ``` * * @implements {ApiResponseTransformer<EventsAppAuthConfig>} * * @example * ```typescript * const transformer = new EventsAppResponseTransformer(); * const response = { * token: "jwt.token.here", * firstName: "John", * lastName: "Doe", * username: "john.doe", * roleName: "ADMIN" * // ... other fields * }; * * if (transformer.canHandle(response)) { * const authResponse = transformer.transform(response); * // Use transformed response * } * ``` */ export class EventsAppResponseTransformer { /** * Checks if the given response matches the Event App API format. * Verifies the presence of required fields specific to Event App responses. * * @param response - The raw API response to check * @returns True if the response contains 'token' and 'roleName' fields */ canHandle(response) { return response.hasOwnProperty('token') && response.hasOwnProperty('roleName'); } /** * Transforms a Event App API response into the standardized AuthResponse format. * Maps API-specific fields to the common auth response structure. * * @param response - The raw API response to transform * @param remember * @returns Standardized auth response with user and token information * @throws Error if required fields are missing from the response */ transform(response, remember) { // Decode the token using jwt-decode let decodedToken; try { decodedToken = jwtDecode(response.token); } catch (error) { console.error('Error decoding JWT token:', error); throw new Error('Failed to decode JWT token. Please check the token format.'); } if (!decodedToken.exp) { throw new Error('Token does not contain an expiry time (exp claim)'); } let expiresIn; if (remember) { // 7 days in seconds expiresIn = 7 * 24 * 60 * 60; } else { // 30 minutes in seconds expiresIn = 30 * 60; } if (expiresIn <= 0) { throw new Error('Token has already expired'); } return { user: { id: response.userId, userName: response.username, firstName: response.firstName, lastName: response.lastName, roles: response.roles, roleName: response.roleName, roleDesc: response.roleDesc, vendorId: response.vendorId, promoterId: response.promoterId, company: response.company, hasIQRetailAccess: response.hasIQRetailAccess ?? false, }, auth: { accessToken: { token: response.token, expiresIn: expiresIn ?? 36000000, }, }, }; } } /** * Transforms authentication responses from the Vas App API format into a standardized AuthResponse. * This transformer handles responses that include both access and refresh tokens. * * Expected API response format: * ```typescript * { * accessToken: string; * refreshToken: string; * accessTokenExpiresIn: number; * refreshTokenExpiresIn: number; * username: string; * roles: string[]; * userId: number; * } * ``` * * @implements {ApiResponseTransformer<VasAppAuthConfig>} * * @example * ```typescript * const transformer = new VasAppResponseTransformer(); * const response = { * accessToken: "access.token.here", * refreshToken: "refresh.token.here", * accessTokenExpiresIn: 3600, * username: "vendor_user" * // ... other fields * }; * * if (transformer.canHandle(response)) { * const authResponse = transformer.transform(response); * // Use transformed response * } * ``` */ export class VasAppResponseTransformer { /** * Checks if the given response matches the Vas App API format. * Verifies the presence of required fields specific to Vendor responses. * * @param response - The raw API response to check * @returns True if the response contains both 'accessToken' and 'refreshToken' fields */ canHandle(response) { return response.hasOwnProperty('accessToken') && response.hasOwnProperty('refreshToken'); } /** * Transforms a Vas App API response into the standardized AuthResponse format. * Maps API-specific fields to the common auth response structure. * * @param response - The raw API response to transform * @param remember * @returns Standardized auth response with user and token information * @throws Error if required fields are missing from the response */ transform(response, remember) { let decodedToken; try { decodedToken = jwtDecode(response.accessToken); } catch (error) { console.error('Error decoding JWT access token:', error); throw new Error('Failed to decode JWT access token. Please check the token format.'); } if (!decodedToken.exp) { throw new Error('Access token does not contain an expiry time (exp claim)'); } let accessExpiresIn; if (remember) { // 7 days in seconds accessExpiresIn = 7 * 24 * 60 * 60; } else { // 30 minutes in seconds accessExpiresIn = 30 * 60; } if (accessExpiresIn <= 0) { throw new Error('Access token has already expired'); } const refreshExpiresIn = remember ? 30 * 24 * 60 * 60 : 24 * 60 * 60; // 30 days or 1 day return { user: { id: response.userId, userName: response.username, roles: response.roles, userId: response.userId, userType: response.userType, userTypeId: response.userTypeId, hasWallet: response.hasWallet ?? false, }, auth: { accessToken: { token: response.accessToken, expiresIn: accessExpiresIn, }, refreshToken: { token: response.refreshToken, expiresIn: refreshExpiresIn, }, }, }; } } /** * Factory class for creating and managing response transformers. * Implements the Factory pattern to dynamically select the appropriate transformer * based on the API response format. * * @example * ```typescript * const apiResponse = await fetchFromApi(); * const transformer = ResponseTransformerFactory.getTransformer(apiResponse); * const authResponse = transformer.transform(apiResponse); * ``` */ export class ResponseTransformerFactory { /** * Collection of available transformers. * Add new transformer instances here to support additional API response formats. * * @private * @static */ static transformers = [ new EventsAppResponseTransformer(), new VasAppResponseTransformer(), ]; /** * Gets the appropriate transformer for the given API response. * Iterates through available transformers and returns the first one that can handle the response. * * @param response - The raw API response to find a transformer for * @returns The first transformer that can handle the response format * @throws Error if no suitable transformer is found * * @example * ```typescript * try { * const transformer = ResponseTransformerFactory.getTransformer(apiResponse); * const authResponse = transformer.transform(apiResponse); * } catch (error) { * console.error('No suitable transformer found:', error); * } * ``` */ static getTransformer(response) { const transformer = this.transformers.find((t) => t.canHandle(response)); if (!transformer) { throw new Error('No suitable transformer found for response format'); } return transformer; } }