@snf/qa-bot-core 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ /**
3
+ * HistoryButton Component
4
+ *
5
+ * A button that displays saved chat history when clicked.
6
+ * Shows in the header when user is logged in.
7
+ *
8
+ * @returns Rendered history button
9
+ */
10
+ declare const HistoryButton: React.FC;
11
+ export default HistoryButton;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Invisible component that stores each chat message with its session ID.
3
+ *
4
+ * Problem: React-Chatbotify stores all messages in a flat list with no session
5
+ * boundaries. When a user has multiple conversations, there's no way to know
6
+ * which messages belong to which conversation. Also, RCB's history storage
7
+ * is opaque and unreliable for session restore.
8
+ *
9
+ * Solution: This component listens for every message injection and stores
10
+ * the full message content in our own localStorage. The history dropdown
11
+ * restores sessions directly from our storage, not RCB's.
12
+ *
13
+ * Deduplication is handled by session-utils (checks message ID).
14
+ *
15
+ * Must be rendered inside ChatBotProvider.
16
+ */
17
+ declare const SessionMessageTracker: React.FC;
18
+ export default SessionMessageTracker;
@@ -1,4 +1,36 @@
1
1
  import type { Settings, Flow } from 'react-chatbotify';
2
+ /**
3
+ * Analytics event types fired by qa-bot-core
4
+ */
5
+ export type QABotAnalyticsEventType = 'qa_bot_opened' | 'qa_bot_closed' | 'qa_new_chat_started' | 'qa_question_asked' | 'qa_response_received' | 'qa_response_error' | 'qa_response_rated' | 'qa_login_prompt_shown';
6
+ /**
7
+ * Analytics event payload
8
+ * Fields are populated based on event type:
9
+ * - qa_bot_opened: sessionId
10
+ * - qa_bot_closed: sessionId, messageCount, durationMs
11
+ * - qa_new_chat_started: sessionId, previousMessageCount
12
+ * - qa_question_asked: sessionId, queryId, questionLength
13
+ * - qa_response_received: sessionId, queryId, responseTimeMs, success, responseLength, hasMetadata
14
+ * - qa_response_error: sessionId, queryId, errorType
15
+ * - qa_response_rated: sessionId, queryId, rating
16
+ * - qa_login_prompt_shown: sessionId
17
+ */
18
+ export interface QABotAnalyticsEvent {
19
+ type: QABotAnalyticsEventType;
20
+ timestamp: number;
21
+ sessionId?: string;
22
+ queryId?: string;
23
+ questionLength?: number;
24
+ responseTimeMs?: number;
25
+ success?: boolean;
26
+ responseLength?: number;
27
+ hasMetadata?: boolean;
28
+ errorType?: string;
29
+ rating?: 'helpful' | 'not_helpful';
30
+ messageCount?: number;
31
+ durationMs?: number;
32
+ previousMessageCount?: number;
33
+ }
2
34
  export interface QABotProps {
3
35
  apiKey: string;
4
36
  qaEndpoint: string;
@@ -31,12 +63,28 @@ export interface QABotProps {
31
63
  * - Does not affect custom flows (tickets, security, etc.)
32
64
  */
33
65
  allowAnonAccess?: boolean;
66
+ /**
67
+ * The acting user's identifier (e.g., email or username).
68
+ * - Sent to the backend in both headers (X-Acting-User) and body (acting_user)
69
+ * - Optional: if not provided, requests will be anonymous
70
+ */
71
+ actingUser?: string;
34
72
  /**
35
73
  * Custom flow steps to merge with the built-in Q&A flow.
36
74
  * Use this to add ticket creation flows, feedback flows, etc.
37
75
  * These steps will be merged into the flow object.
38
76
  */
39
77
  customFlow?: Flow;
78
+ /**
79
+ * Callback fired when trackable events occur.
80
+ * Use this to wire up analytics (GTM, GA4, etc.)
81
+ *
82
+ * @example
83
+ * onAnalyticsEvent={(event) => {
84
+ * window.dataLayer?.push({ event: event.type, ...event });
85
+ * }}
86
+ */
87
+ onAnalyticsEvent?: (event: QABotAnalyticsEvent) => void;
40
88
  }
41
89
  /**
42
90
  * Default values for overridable props
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { QABotAnalyticsEvent } from '../config';
3
+ interface AnalyticsContextValue {
4
+ trackEvent: (event: Omit<QABotAnalyticsEvent, 'timestamp'>) => void;
5
+ }
6
+ interface AnalyticsProviderProps {
7
+ onAnalyticsEvent?: (event: QABotAnalyticsEvent) => void;
8
+ getSessionId: () => string | null;
9
+ children: React.ReactNode;
10
+ }
11
+ export declare const AnalyticsProvider: React.FC<AnalyticsProviderProps>;
12
+ export declare const useAnalytics: () => AnalyticsContextValue;
13
+ export {};
@@ -1,10 +1,14 @@
1
1
  import React from 'react';
2
2
  interface SessionContextType {
3
+ getSessionId: () => string;
4
+ setSessionId: (sessionId: string) => void;
3
5
  resetSession: () => void;
4
6
  clearResettingFlag: () => void;
5
7
  }
6
8
  export declare const SessionProvider: React.FC<{
7
9
  children: React.ReactNode;
10
+ getSessionId: () => string;
11
+ setSessionId: (sessionId: string) => void;
8
12
  resetSession: () => void;
9
13
  clearResettingFlag: () => void;
10
14
  }>;
@@ -1,4 +1,5 @@
1
1
  import QABot from './components/QABot';
2
+ import type { QABotAnalyticsEvent } from './config';
2
3
  import './styles/index.css';
3
4
  export { QABot };
4
5
  export { FileUploadComponent } from './components/FileUploadComponent';
@@ -9,7 +10,7 @@ export { fileToBase64, filesToBase64, validateFileSize, formatFileSize } from '.
9
10
  export type { ProcessedFile } from './utils/file-utils';
10
11
  export { applyFlowSettings } from './utils/flow-settings';
11
12
  export type { FlowSettingsOptions } from './utils/flow-settings';
12
- export type { QABotProps, BotControllerHandle } from './config';
13
+ export type { QABotProps, BotControllerHandle, QABotAnalyticsEvent, QABotAnalyticsEventType } from './config';
13
14
  /**
14
15
  * ===========================================
15
16
  * PROGRAMMATIC API TYPES
@@ -34,6 +35,7 @@ interface QABotConfig {
34
35
  footerText?: string;
35
36
  footerLink?: string;
36
37
  tooltipText?: string;
38
+ onAnalyticsEvent?: (event: QABotAnalyticsEvent) => void;
37
39
  }
38
40
  interface QABotInstance {
39
41
  addMessage: (message: string) => void;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * fix-markdown-links.ts
3
+ *
4
+ * PRAGMATIC HACK: This file exists because react-chatbotify's MarkdownRenderer plugin
5
+ * doesn't process messages injected via replaceMessages() (used for history restoration).
6
+ *
7
+ * After trying several "proper" approaches (tag manipulation, JSX conversion, HTML strings),
8
+ * none worked without breaking message bubble styling. This DOM post-processing approach
9
+ * is a pragmatic solution that:
10
+ * - Preserves all message styling (bubbles render correctly first)
11
+ * - Simply finds raw markdown link patterns [text](url) in rendered text
12
+ * - Replaces them with actual <a> elements
13
+ *
14
+ * Only used after history restoration, not during normal chat flow.
15
+ */
16
+ /**
17
+ * Fixes markdown links in chat messages after they've been rendered.
18
+ * Call this after replaceMessages() to convert [text](url) patterns to clickable links.
19
+ */
20
+ export declare const fixMarkdownLinksInDom: () => void;
@@ -1,29 +1,35 @@
1
1
  import React from 'react';
2
+ import type { QABotAnalyticsEvent } from '../../config';
2
3
  /**
3
- * Creates the basic Q&A conversation flow
4
- * Handles questions, responses, and optional ratings
5
- *
6
- * @param {Object} params Configuration
7
- * @param {string} params.endpoint Q&A API endpoint (required)
8
- * @param {string} params.ratingEndpoint Rating API endpoint (optional)
9
- * @param {string} params.apiKey API key for authentication (optional)
10
- * @param {Function} params.sessionId Function that returns current session ID
11
- * @param {Function} params.isResetting Function that returns whether we're currently resetting
12
- * @param {boolean} params.isLoggedIn Whether the user is logged in (required)
13
- * @param {boolean} params.allowAnonAccess Allow Q&A without login (default: false)
14
- * @param {string} params.loginUrl Login URL to redirect to (optional)
15
- * @returns {Object} Q&A flow configuration
4
+ * Configuration for creating a Q&A flow
16
5
  */
17
- export declare const createQAFlow: ({ endpoint, ratingEndpoint, apiKey, sessionId: getSessionId, isResetting, isLoggedIn, allowAnonAccess, loginUrl }: {
18
- endpoint: any;
19
- ratingEndpoint: any;
20
- apiKey: any;
21
- sessionId: any;
6
+ export interface CreateQAFlowParams {
7
+ /** Q&A API endpoint (required) */
8
+ endpoint: string;
9
+ /** Rating API endpoint (optional) */
10
+ ratingEndpoint?: string;
11
+ /** API key for authentication (optional) */
12
+ apiKey?: string;
13
+ /** Function that returns current session ID */
14
+ sessionId: () => string | null;
15
+ /** Function that returns whether we're currently resetting */
22
16
  isResetting?: () => boolean;
23
- isLoggedIn: any;
17
+ /** Whether the user is logged in (required) */
18
+ isLoggedIn: boolean;
19
+ /** Allow Q&A without login (default: false) */
24
20
  allowAnonAccess?: boolean;
21
+ /** Login URL to redirect to (optional) */
25
22
  loginUrl?: string;
26
- }) => {
23
+ /** The acting user's identifier (optional) */
24
+ actingUser?: string;
25
+ /** Callback for analytics events (optional) */
26
+ onAnalyticsEvent?: (event: QABotAnalyticsEvent) => void;
27
+ }
28
+ /**
29
+ * Creates the basic Q&A conversation flow
30
+ * Handles questions, responses, and optional ratings
31
+ */
32
+ export declare const createQAFlow: ({ endpoint, ratingEndpoint, apiKey, sessionId: getSessionId, isResetting, isLoggedIn, allowAnonAccess, loginUrl, actingUser, onAnalyticsEvent }: CreateQAFlowParams) => {
27
33
  qa_loop: {
28
34
  message: string;
29
35
  component: React.JSX.Element;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Logger utility for QA Bot Core
3
+ *
4
+ * Controls debug logging via localStorage:
5
+ * - QA_BOT_DEBUG: Set to 'true' to enable debug logging and version info
6
+ *
7
+ * Usage for consumers:
8
+ * localStorage.setItem('QA_BOT_DEBUG', 'true'); // Enable debug logs + version
9
+ */
10
+ export declare const LIB_VERSION = "0.2.6";
11
+ export declare const logger: {
12
+ version: () => void;
13
+ session: (action: string, ...args: unknown[]) => void;
14
+ history: (action: string, ...args: unknown[]) => void;
15
+ warn: (...args: unknown[]) => void;
16
+ error: (...args: unknown[]) => void;
17
+ };
@@ -1,2 +1,54 @@
1
+ /**
2
+ * Stored message structure - minimal data needed for restore
3
+ */
4
+ export interface StoredMessage {
5
+ id: string;
6
+ content: string;
7
+ sender: string;
8
+ type: string;
9
+ timestamp: number;
10
+ }
11
+ /**
12
+ * Session data structure
13
+ */
14
+ export interface SessionMessageData {
15
+ messages: StoredMessage[];
16
+ startedAt: string;
17
+ preview: string;
18
+ }
19
+ export interface SessionMessagesStore {
20
+ [sessionId: string]: SessionMessageData;
21
+ }
1
22
  export declare const generateSessionId: () => string;
2
- export declare const getOrCreateSessionId: () => string;
23
+ /**
24
+ * Get the session messages store from localStorage
25
+ */
26
+ export declare const getSessionMessagesStore: () => SessionMessagesStore;
27
+ /**
28
+ * Add a message to a session's storage.
29
+ * Called when RcbPreInjectMessageEvent fires.
30
+ * Stores the full message so we can restore sessions without relying on RCB's history.
31
+ */
32
+ export declare const addMessageToSession: (sessionId: string, messageId: string, messageContent: string, sender: string, type: string) => void;
33
+ /**
34
+ * Get all sessions with their metadata (for history display)
35
+ */
36
+ export declare const getAllSessions: () => Array<{
37
+ sessionId: string;
38
+ } & SessionMessageData>;
39
+ /**
40
+ * Get all stored messages for a specific session.
41
+ * Returns messages in the format needed for RCB's replaceMessages().
42
+ */
43
+ export declare const getSessionMessages: (sessionId: string) => StoredMessage[];
44
+ /**
45
+ * Get the message count for a session.
46
+ * Used for analytics (qa_bot_closed, qa_new_chat_started events).
47
+ */
48
+ export declare const getSessionMessageCount: (sessionId: string) => number;
49
+ /**
50
+ * Compute how long a session has been active (in milliseconds).
51
+ * Calculates the difference between now and the session's startedAt timestamp.
52
+ * Used for analytics (qa_bot_closed event).
53
+ */
54
+ export declare const computeSessionDurationMs: (sessionId: string) => number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snf/qa-bot-core",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "A configurable chatbot setup for quick integration of RAG-powered Q&A and rating system",
5
5
  "main": "./dist/qa-bot-core.umd.cjs",
6
6
  "module": "./dist/qa-bot-core.js",