@aslaluroba/help-center
Version:
A powerful and customizable help center widget for Angular applications with real-time chat functionality, AI assistance, multi-language support, and user feedback collection.
630 lines (617 loc) • 23.2 kB
TypeScript
import * as _angular_core from '@angular/core';
import { OnInit, OnDestroy, ElementRef, InjectionToken, PipeTransform } from '@angular/core';
import { Observable } from 'rxjs';
type Language = 'en' | 'ar';
interface TokenResponse {
token: string;
expiresIn: number;
}
interface Option {
id: string;
helpScreenId: string;
parentOptionId: string | null;
nestedOptions: Option[];
title: string;
paragraphs: string[];
chatWithUs: boolean;
assistantId?: string;
assistant?: {
id: string;
tenantId: string;
tenant: {
id: string;
name: string;
key: string;
};
name: string;
openAIAssistantId: string;
greeting: string;
closing: string;
};
hasNestedOptions: boolean;
order: number;
icon?: string;
}
interface Message {
id: string | number;
sender: 'user' | 'assistant' | 'agent';
senderType: number;
messageContent: string;
sentAt: Date;
isSeen: boolean;
attachmentIds?: string[];
isReviewMessage?: boolean;
}
interface Tenant {
id: string;
name: string;
key: string;
logoUrl?: string | null;
autoCloseSessions?: boolean;
autoCloseSessionsAfter?: number;
settings?: {
description?: string;
theme?: {
primaryColor?: string;
secondaryColor?: string;
};
};
}
interface Assistant {
id: string;
tenantId: string;
tenant: Tenant;
name: string;
openAIAssistantId: string;
greeting: string;
closing: string;
}
interface HelpScreenFile {
id: string;
name: string;
url: string;
type: string;
size?: number;
}
interface HelpScreenOption {
id: string;
helpScreenId: string;
parentOptionId: string | null;
nestedOptions: HelpScreenOption[];
title: string;
paragraphs: string[];
files: HelpScreenFile[];
chatWithUs: boolean;
assistantId?: string;
assistant?: Assistant;
hasNestedOptions: boolean;
order: number;
icon?: string;
}
interface HelpScreenData {
id: string;
tenantId: string;
tenant: Tenant;
title: string;
description: string;
options: HelpScreenOption[];
chatWithUs: boolean;
}
interface PresignUploadRequestDto {
name: string;
contentType: string;
sizeBytes: number;
pathData: {
type: number;
chatSessionId: string;
};
}
interface PresignUploadResponse {
id: string;
uploadUrl: string;
path: string;
expiresAt: string;
}
interface PresignDownloadResponse {
id: string;
name: string;
downloadUrl: string;
contentType: string;
expiresAt: string;
}
interface SelectedFileDto {
file: File;
previewUrl: string;
uploading: boolean;
uploadedId: string | null;
error: string | null;
}
interface UploadResult {
fileId: string;
success: boolean;
error?: string;
}
declare class HelpCenterWidgetComponent implements OnInit, OnDestroy {
getToken: _angular_core.InputSignal<() => Promise<string>>;
helpScreenId: _angular_core.InputSignal<string>;
showArrow: _angular_core.InputSignal<boolean>;
messageLabel: _angular_core.InputSignal<string | null>;
currentLang: _angular_core.InputSignal<string>;
primaryColor: _angular_core.InputSignal<string>;
logoUrl: _angular_core.InputSignal<string>;
chatMessagesContainer: ElementRef;
isRTL: _angular_core.Signal<boolean>;
isPopupOpen: _angular_core.WritableSignal<boolean>;
helpScreenData: _angular_core.WritableSignal<HelpScreenData | null>;
status: _angular_core.WritableSignal<"failed" | "idle" | "loading" | "succeeded">;
error: _angular_core.WritableSignal<string | null>;
showArrowAnimation: _angular_core.WritableSignal<boolean>;
showTooltip: _angular_core.WritableSignal<boolean>;
sessionId: _angular_core.WritableSignal<string | null>;
isAblyConnected: _angular_core.WritableSignal<boolean>;
isChatClosed: _angular_core.WritableSignal<boolean>;
showChat: _angular_core.WritableSignal<boolean>;
messageText: _angular_core.WritableSignal<string>;
isTyping: _angular_core.WritableSignal<boolean>;
messages: _angular_core.WritableSignal<Message[]>;
showHelpScreenData: _angular_core.WritableSignal<boolean>;
chatIsLoading: _angular_core.WritableSignal<boolean>;
ablyToken: _angular_core.WritableSignal<string | null>;
needsAgent: _angular_core.WritableSignal<boolean>;
assistantStatus: _angular_core.WritableSignal<"typing" | "idle">;
selectedOption: _angular_core.WritableSignal<Option | null>;
selectedNestedOption: _angular_core.WritableSignal<Option | null>;
showEndChatConfirmation: _angular_core.WritableSignal<boolean>;
showStartNewChatConfirmation: _angular_core.WritableSignal<boolean>;
showReviewDialog: _angular_core.WritableSignal<boolean>;
isSubmittingReview: _angular_core.WritableSignal<boolean>;
isStartingNewChat: _angular_core.WritableSignal<boolean>;
pendingNewChatOption: _angular_core.WritableSignal<Option | null>;
hasUserSentMessages: _angular_core.WritableSignal<boolean>;
closedSessionIdForReview: _angular_core.WritableSignal<string | null>;
waitingForSessionEndConfirmation: _angular_core.WritableSignal<boolean>;
private isClosingChatSession;
private apiService;
private translationService;
private themeService;
private chatSessionService;
private actionHandlerService;
private fileUploadService;
private destroyRef;
private themeEffectRef?;
private languageEffectRef?;
constructor();
/**
* Registers action handlers for AI response actions.
* This uses the ActionHandlerService for extensible, maintainable action handling.
*/
private registerActionHandlers;
ngOnInit(): void;
ngOnDestroy(): void;
handleTogglePopup(): Promise<void>;
private fetchHelpScreenData;
createChatSession(option?: Option): Promise<{
chatSession: {
id: string;
};
ablyToken: string;
}>;
sendMessage(event?: {
text: string;
attachmentIds: string[];
pendingFiles?: File[];
} | string): Promise<void>;
/**
* Called when user attaches files but there is no session yet.
* Creates a session so that chat-input can upload the files; send stays disabled until upload completes.
*/
handleRequestSessionForAttachments(): Promise<void>;
handleReceiveMessage(message: string | {
content: string;
attachments?: string[];
}, senderType: number, needsAgent: boolean): void;
private getSenderType;
private hasActiveChatSession;
private isWelcomeMessage;
handleStartNewChat(option: Option): Promise<void>;
private startNewChatSession;
handleStartChat(option: Option): Promise<void>;
handleEndChat(): Promise<void>;
confirmEndChat(): Promise<void>;
handleReviewSubmit(reviewData: {
rating: number;
comment: string;
}): Promise<void>;
handleReviewClose(): void;
handleReviewSkip(): Promise<void>;
private endChatSession;
private closeSessionOnly;
cancelEndChat(): void;
closeEndChat(): void;
confirmStartNewChat(): Promise<void>;
cancelStartNewChat(): void;
closeStartNewChat(): void;
private clearCurrentChat;
private startNewChatWithOption;
handleClosePopup(): Promise<void>;
handleMinimizePopup(): void;
handleCloseArrowAnimation(): void;
handleBack(): void;
handleShowChat(): void;
selectOption(option: Option): void;
selectNestedOption(nestedOption: Option): void;
handleShowHelpScreenData(): void;
private scrollTimeout?;
private scrollToBottom;
getDirection(): "ltr" | "rtl";
get helpScreenDataList(): {
icon: string;
title: string;
description: string;
actionLabel: string;
action: (() => Promise<void>) | null;
}[];
navigateToUrl(url: string): void;
private addReviewMessageToChat;
handleEndSessionReceived(): void;
private handleEndSessionConfirmed;
handleReviewSubmitFromChat(reviewData: {
rating: number;
comment: string;
}): Promise<void>;
handleReviewSkipFromChat(): Promise<void>;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HelpCenterWidgetComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HelpCenterWidgetComponent, "app-help-center-widget", never, { "getToken": { "alias": "getToken"; "required": true; "isSignal": true; }; "helpScreenId": { "alias": "helpScreenId"; "required": true; "isSignal": true; }; "showArrow": { "alias": "showArrow"; "required": false; "isSignal": true; }; "messageLabel": { "alias": "messageLabel"; "required": false; "isSignal": true; }; "currentLang": { "alias": "currentLang"; "required": false; "isSignal": true; }; "primaryColor": { "alias": "primaryColor"; "required": false; "isSignal": true; }; "logoUrl": { "alias": "logoUrl"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
}
/**
* URL for the loading screen animated logo (e.g. animatedLogo.gif).
* When using the library as an npm package, copy the library's assets to your app
* (see README "Assets setup") or provide your own URL here.
*/
declare const HELP_CENTER_LOADING_LOGO_URL: InjectionToken<string>;
type GetTokenFn = () => Promise<string>;
/**
* Service for managing help center configuration.
*
* Stores configuration such as API base URL and token retrieval function.
* This service is used internally by other services to access configuration.
*
* @publicApi
*/
declare class HelpCenterConfigService {
private _apiBaseUrl;
private _getTokenFn?;
setApiBaseUrl(url: string): void;
getApiBaseUrl(): string;
setGetTokenFn(fn: GetTokenFn): void;
getTokenFn(): GetTokenFn | undefined;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HelpCenterConfigService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<HelpCenterConfigService>;
}
/**
* Service for handling API requests with automatic authentication token management.
*
* Features:
* - Automatic token refresh on expiry
* - Token validation and format checking
* - Secure token storage using sessionStorage
* - Endpoint validation to prevent SSRF attacks
*
* @publicApi
*/
declare class ApiService {
private getTokenFunction;
private baseUrl;
/**
* Initialize the API service with authentication configuration.
*
* This must be called before making any API requests. The service will use
* the provided token function to fetch and refresh tokens automatically.
*
* @param config Configuration object containing token function and optional base URL
* @throws Error if getToken function is not provided
*
* @example
* ```typescript
* apiService.initialize({
* getToken: async () => {
* const response = await fetch('/auth/token');
* const data = await response.json();
* return data.token;
* },
* baseUrl: 'https://api.example.com'
* });
* ```
*/
initialize(config: ApiConfig): void;
/**
* Validate token format
* JWT tokens must have exactly 3 parts separated by dots (header.payload.signature)
*/
private validateToken;
/**
* Retrieves a valid authentication token, fetching a new one if expired.
*
* Tokens are cached for 15 minutes. The service provides backward compatibility:
* - Checks localStorage first for existing tokens (backward compatibility)
* - Falls back to sessionStorage if no token found in localStorage
* - New tokens are stored in sessionStorage (preferred) or localStorage (fallback)
* - Automatically migrates tokens from localStorage to sessionStorage when found
*
* After expiry, a new token is automatically fetched using the configured getToken function.
*
* @param forceRefresh If true, forces a new token fetch even if current token is valid
* @returns Promise resolving to a valid authentication token
* @throws Error if API service is not initialized or token format is invalid
*/
getValidToken(forceRefresh?: boolean): Promise<string>;
private fetchWithAuth;
/**
* Validate endpoint to prevent SSRF vulnerabilities
*
* Protects against:
* - Absolute URLs with any protocol (case-insensitive)
* - Protocol-relative URLs
* - Dangerous protocols (ftp, file, data, javascript, etc.)
* - URL-encoded path traversal
* - Double-encoded attacks
*/
private validateEndpoint;
/**
* Makes an authenticated API request with automatic token management.
*
* This method automatically:
* - Validates the endpoint to prevent SSRF attacks
* - Adds authentication headers with a valid token
* - Retries with a fresh token if authentication fails
* - Handles errors and returns appropriate error messages
*
* @param endpoint API endpoint path (relative to baseUrl)
* @param method HTTP method (default: 'GET')
* @param body Request body object (will be JSON stringified)
* @param customHeaders Additional headers to include in the request
* @returns Promise resolving to the Response object
* @throws Error if endpoint validation fails, request fails, or authentication fails
*
* @example
* ```typescript
* // GET request
* const response = await apiService.apiRequest('client/help-screens/123');
* const data = await response.json();
*
* // POST request
* const response = await apiService.apiRequest(
* 'client/chat-sessions',
* 'POST',
* { helpScreenId: '123' }
* );
* ```
*/
apiRequest<T = unknown>(endpoint: string, method?: string, body?: T | null, customHeaders?: Record<string, string>): Promise<Response>;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ApiService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ApiService>;
}
/**
* Service for retrieving authentication tokens from the configured token function.
*
* This service acts as a wrapper around the configured token retrieval function,
* providing a consistent interface for token management.
*
* @publicApi
*/
declare class TokenService {
private config;
/**
* Retrieves an authentication token using the configured token function.
*
* @returns Promise resolving to a TokenResponse containing the token and expiry time
* @throws Error if no token function is configured
*/
getToken(): Promise<TokenResponse>;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TokenService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<TokenService>;
}
type TranslationKey = 'ChatIntroMessage' | 'BabylaiTitle' | 'BabylaiDescription' | 'ChatNow' | 'TryBableAI' | 'ContactUs' | 'HelpCenter' | 'BabylAI' | 'ChatPlaceholder' | 'PoweredByBabylAI' | 'EndChat' | 'LeavingDialogTitle' | 'LeavingDialogBody' | 'StartNewChatDialogTitle' | 'StartNewChatDialogBody' | 'ReviewDialogTitle' | 'ReviewDialogDescription' | 'ReviewDialogRatingLabel' | 'ReviewDialogCommentLabel' | 'ReviewDialogCommentPlaceholder' | 'ReviewDialogSubmitButton' | 'ReviewDialogSkipButton' | 'Confirm' | 'Cancel' | 'Close' | 'Back' | 'title' | 'ErrorFetchingHelpScreen' | 'ErrorSendingMessage' | 'ErrorStartingChat' | 'ErrorEndingChat' | 'ErrorSubmittingReview' | 'ErrorClosingChat' | 'ErrorCreatingSession' | 'ErrorNetworkFailure' | 'ErrorUnknown' | 'ErrorMessageTooLong' | 'ErrorMessageEmpty' | 'CloseChat' | 'Continue';
/**
* Service for managing translations and language switching.
*
* Supports multiple languages (currently English and Arabic) with RTL support.
* Provides reactive language changes through Observable pattern.
*
* @publicApi
*/
declare class TranslationService {
private translations;
private _currentLang;
readonly currentLang: Observable<Language>;
/**
* Translates a translation key to the current language.
*
* @param key Translation key to look up
* @returns Translated string in the current language, or the key itself if translation not found
*
* @example
* ```typescript
* const message = translationService.translate('ChatNow');
* // Returns 'Let\'s Chat' in English or 'دعنا نتحدث' in Arabic
* ```
*/
translate(key: TranslationKey): string;
/**
* Sets the current language for translations.
*
* @param lang Language code ('en' or 'ar')
*
* @example
* ```typescript
* translationService.setLanguage('ar'); // Switch to Arabic
* ```
*/
setLanguage(lang: Language): void;
/**
* Gets the current language code.
*
* @returns Current language code ('en' or 'ar')
*/
getCurrentLang(): Language;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TranslationService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<TranslationService>;
}
/**
* Service for managing chat session lifecycle and operations.
*
* Handles:
* - Chat session creation and management
* - Ably connection management
* - Message sending operations
*
* @publicApi
*/
declare class ChatSessionService {
private apiService;
private actionHandlerService;
/**
* Creates a new chat session with the specified option.
*
* @param option The help screen option to create a chat session for
* @param helpScreenId The help screen ID
* @param currentLang Current language code for API headers
* @returns Promise resolving to session data including sessionId and ablyToken
* @throws Error if session creation fails
*/
createSession(option: Option, helpScreenId: string, currentLang: string): Promise<{
chatSession: {
id: string;
};
ablyToken: string;
}>;
/**
* Establishes Ably real-time connection for a chat session.
*
* @param sessionId The chat session ID
* @param ablyToken The Ably authentication token
* @param onMessageReceived Callback function for received messages
* @param tenantId The tenant ID for the connection
* @param option Optional option for token refresh (needed for token renewal)
* @param helpScreenId Optional help screen ID for token refresh
* @param currentLang Optional current language for token refresh
* @param onActionReceived Optional callback function for handling action types
*/
establishAblyConnection(sessionId: string, ablyToken: string, onMessageReceived: (message: string | {
content: string;
attachments?: string[];
}, senderType: number, needsAgent: boolean) => void, tenantId: string, option?: Option, helpScreenId?: string, currentLang?: string, onActionReceived?: (actionType: string, messageData: any) => void | Promise<void>): Promise<void>;
/**
* Sends a message in an active chat session.
*
* @param sessionId The chat session ID
* @param messageContent The message content to send
* @param currentLang Current language code for API headers
* @throws Error if message sending fails
*/
sendMessage(sessionId: string, messageContent: string, currentLang: string, attachmentIds?: string[]): Promise<void>;
/**
* Closes a chat session.
*
* @param sessionId The chat session ID to close
* @param currentLang Current language code for API headers
* @returns Promise resolving to the close response
* @throws Error if session closing fails
*/
closeSession(sessionId: string, currentLang: string): Promise<unknown>;
/**
* Submits a review for a chat session.
*
* @param sessionId The chat session ID
* @param rating Rating value (1-5)
* @param comment Review comment (10-500 characters)
* @param currentLang Current language code for API headers
* @throws Error if review submission fails
*/
submitReview(sessionId: string, rating: number, comment: string, currentLang: string): Promise<void>;
/**
* Stops the Ably connection.
*/
stopConnection(): Promise<void>;
/**
* Checks if Ably connection is active.
*
* @returns True if connection is active, false otherwise
*/
isConnectionActive(): boolean;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatSessionService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ChatSessionService>;
}
/**
* Service for managing language switching.
*
* Provides a simplified interface for switching between supported languages.
* This service wraps TranslationService for easier language management.
*
* @publicApi
*/
declare class LanguageService {
private translationService;
/**
* Switches the application language.
*
* @param language Language code to switch to ('en' or 'ar')
*
* @example
* ```typescript
* languageService.switchLanguage('ar'); // Switch to Arabic
* ```
*/
switchLanguage(language: Language): void;
/**
* Gets the current application language.
*
* @returns Current language code ('en' or 'ar')
*/
getCurrentLang(): Language;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LanguageService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<LanguageService>;
}
/**
* Angular pipe for translating keys in templates.
*
* Usage in templates:
* ```html
* {{ 'ChatNow' | translate }}
* ```
*
* @publicApi
*/
declare class TranslatePipe implements PipeTransform {
private translationService;
/**
* Transforms a translation key into the translated string for the current language.
*
* @param key Translation key to look up
* @returns Translated string in the current language
*/
transform(key: TranslationKey): string;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TranslatePipe, never>;
static ɵpipe: _angular_core.ɵɵPipeDeclaration<TranslatePipe, "translate", true>;
}
/**
* Configuration interface for API service initialization
*
* @publicApi
*/
interface ApiConfig {
/**
* Function that returns a promise resolving to an authentication token
* This function is called when tokens need to be refreshed
*/
getToken: () => Promise<string>;
/**
* Optional base URL for API requests
* Defaults to 'https://babylai.net/api' if not provided
* Should use HTTPS in production environments
*/
baseUrl?: string;
}
export { ApiService, ChatSessionService, HELP_CENTER_LOADING_LOGO_URL, HelpCenterConfigService, HelpCenterWidgetComponent, LanguageService, TokenService, TranslatePipe, TranslationService };
export type { ApiConfig, Assistant, GetTokenFn, HelpScreenData, HelpScreenFile, HelpScreenOption, Language, Message, Option, PresignDownloadResponse, PresignUploadRequestDto, PresignUploadResponse, SelectedFileDto, Tenant, TokenResponse, TranslationKey, UploadResult };
//# sourceMappingURL=aslaluroba-help-center.d.ts.map