@om_patel_26/chat-widget 1.0.1
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.
- package/README.md +276 -0
- package/dist/_virtual/_plugin-vue_export-helper.cjs.js +2 -0
- package/dist/_virtual/_plugin-vue_export-helper.cjs.js.map +1 -0
- package/dist/_virtual/_plugin-vue_export-helper.esm.js +11 -0
- package/dist/_virtual/_plugin-vue_export-helper.esm.js.map +1 -0
- package/dist/adapters/vue/index.d.ts +7 -0
- package/dist/adapters/vue/index.d.ts.map +1 -0
- package/dist/adapters/vue/useChatMode.d.ts +21 -0
- package/dist/adapters/vue/useChatMode.d.ts.map +1 -0
- package/dist/components/ChatWidget.d.ts +43 -0
- package/dist/components/ChatWidget.d.ts.map +1 -0
- package/dist/components/ChatWidget.vue.cjs.js +2 -0
- package/dist/components/ChatWidget.vue.cjs.js.map +1 -0
- package/dist/components/ChatWidget.vue.cjs2.js +2 -0
- package/dist/components/ChatWidget.vue.cjs2.js.map +1 -0
- package/dist/components/ChatWidget.vue.esm.js +8 -0
- package/dist/components/ChatWidget.vue.esm.js.map +1 -0
- package/dist/components/ChatWidget.vue.esm2.js +331 -0
- package/dist/components/ChatWidget.vue.esm2.js.map +1 -0
- package/dist/composables/useChatWidget.cjs.js +2 -0
- package/dist/composables/useChatWidget.cjs.js.map +1 -0
- package/dist/composables/useChatWidget.d.ts +34 -0
- package/dist/composables/useChatWidget.d.ts.map +1 -0
- package/dist/composables/useChatWidget.esm.js +72 -0
- package/dist/composables/useChatWidget.esm.js.map +1 -0
- package/dist/core/stateManager.cjs.js +2 -0
- package/dist/core/stateManager.cjs.js.map +1 -0
- package/dist/core/stateManager.d.ts +136 -0
- package/dist/core/stateManager.d.ts.map +1 -0
- package/dist/core/stateManager.esm.js +907 -0
- package/dist/core/stateManager.esm.js.map +1 -0
- package/dist/core/types.d.ts +66 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/entry/next.d.ts +9 -0
- package/dist/entry/next.d.ts.map +1 -0
- package/dist/entry/nuxt.d.ts +10 -0
- package/dist/entry/nuxt.d.ts.map +1 -0
- package/dist/entry/react.d.ts +10 -0
- package/dist/entry/react.d.ts.map +1 -0
- package/dist/entry/vanilla.d.ts +33 -0
- package/dist/entry/vanilla.d.ts.map +1 -0
- package/dist/entry/vite.d.ts +11 -0
- package/dist/entry/vite.d.ts.map +1 -0
- package/dist/entry/vue.d.ts +11 -0
- package/dist/entry/vue.d.ts.map +1 -0
- package/dist/hooks/useChatMode.d.ts +17 -0
- package/dist/hooks/useChatMode.d.ts.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +25 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jws/compact/sign.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/jws/compact/sign.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jws/compact/sign.esm.js +21 -0
- package/dist/node_modules/jose/dist/browser/jws/compact/sign.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jws/flattened/sign.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/jws/flattened/sign.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jws/flattened/sign.esm.js +84 -0
- package/dist/node_modules/jose/dist/browser/jws/flattened/sign.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jwt/produce.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/jwt/produce.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jwt/produce.esm.js +72 -0
- package/dist/node_modules/jose/dist/browser/jwt/produce.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jwt/sign.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/jwt/sign.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/jwt/sign.esm.js +22 -0
- package/dist/node_modules/jose/dist/browser/jwt/sign.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/key/import.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/key/import.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/key/import.esm.js +11 -0
- package/dist/node_modules/jose/dist/browser/key/import.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/buffer_utils.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/buffer_utils.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/buffer_utils.esm.js +18 -0
- package/dist/node_modules/jose/dist/browser/lib/buffer_utils.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/check_key_type.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/check_key_type.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/check_key_type.esm.js +77 -0
- package/dist/node_modules/jose/dist/browser/lib/check_key_type.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/crypto_key.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/crypto_key.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/crypto_key.esm.js +101 -0
- package/dist/node_modules/jose/dist/browser/lib/crypto_key.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/epoch.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/epoch.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/epoch.esm.js +5 -0
- package/dist/node_modules/jose/dist/browser/lib/epoch.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.esm.js +32 -0
- package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_disjoint.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/is_disjoint.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_disjoint.esm.js +25 -0
- package/dist/node_modules/jose/dist/browser/lib/is_disjoint.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_jwk.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/is_jwk.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_jwk.esm.js +20 -0
- package/dist/node_modules/jose/dist/browser/lib/is_jwk.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_object.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/is_object.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/is_object.esm.js +20 -0
- package/dist/node_modules/jose/dist/browser/lib/is_object.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/secs.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/secs.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/secs.esm.js +59 -0
- package/dist/node_modules/jose/dist/browser/lib/secs.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/validate_crit.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/lib/validate_crit.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/lib/validate_crit.esm.js +34 -0
- package/dist/node_modules/jose/dist/browser/lib/validate_crit.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/asn1.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/asn1.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/asn1.esm.js +103 -0
- package/dist/node_modules/jose/dist/browser/runtime/asn1.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/base64url.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/base64url.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/base64url.esm.js +43 -0
- package/dist/node_modules/jose/dist/browser/runtime/base64url.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/check_key_length.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/check_key_length.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/check_key_length.esm.js +12 -0
- package/dist/node_modules/jose/dist/browser/runtime/check_key_length.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.esm.js +25 -0
- package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/is_key_like.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/is_key_like.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/is_key_like.esm.js +13 -0
- package/dist/node_modules/jose/dist/browser/runtime/is_key_like.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.esm.js +107 -0
- package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/normalize_key.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/normalize_key.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/normalize_key.esm.js +71 -0
- package/dist/node_modules/jose/dist/browser/runtime/normalize_key.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/sign.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/sign.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/sign.esm.js +14 -0
- package/dist/node_modules/jose/dist/browser/runtime/sign.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.esm.js +32 -0
- package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/webcrypto.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/runtime/webcrypto.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/runtime/webcrypto.esm.js +7 -0
- package/dist/node_modules/jose/dist/browser/runtime/webcrypto.esm.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/util/errors.cjs.js +2 -0
- package/dist/node_modules/jose/dist/browser/util/errors.cjs.js.map +1 -0
- package/dist/node_modules/jose/dist/browser/util/errors.esm.js +131 -0
- package/dist/node_modules/jose/dist/browser/util/errors.esm.js.map +1 -0
- package/dist/nuxt.cjs.js +2 -0
- package/dist/nuxt.cjs.js.map +1 -0
- package/dist/nuxt.esm.js +8 -0
- package/dist/nuxt.esm.js.map +1 -0
- package/dist/services/chatService.cjs.js +2 -0
- package/dist/services/chatService.cjs.js.map +1 -0
- package/dist/services/chatService.d.ts +144 -0
- package/dist/services/chatService.d.ts.map +1 -0
- package/dist/services/chatService.esm.js +482 -0
- package/dist/services/chatService.esm.js.map +1 -0
- package/dist/services/dialogflowClient.cjs.js +2 -0
- package/dist/services/dialogflowClient.cjs.js.map +1 -0
- package/dist/services/dialogflowClient.d.ts +36 -0
- package/dist/services/dialogflowClient.d.ts.map +1 -0
- package/dist/services/dialogflowClient.esm.js +282 -0
- package/dist/services/dialogflowClient.esm.js.map +1 -0
- package/dist/services/sessionManager.cjs.js +2 -0
- package/dist/services/sessionManager.cjs.js.map +1 -0
- package/dist/services/sessionManager.d.ts +13 -0
- package/dist/services/sessionManager.d.ts.map +1 -0
- package/dist/services/sessionManager.esm.js +48 -0
- package/dist/services/sessionManager.esm.js.map +1 -0
- package/dist/styles.css +0 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/dialogflowHandler.d.ts +31 -0
- package/dist/utils/dialogflowHandler.d.ts.map +1 -0
- package/dist/utils/frameworkDetector.d.ts +17 -0
- package/dist/utils/frameworkDetector.d.ts.map +1 -0
- package/dist/utils/sanitize.cjs.js +2 -0
- package/dist/utils/sanitize.cjs.js.map +1 -0
- package/dist/utils/sanitize.d.ts +25 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.esm.js +57 -0
- package/dist/utils/sanitize.esm.js.map +1 -0
- package/dist/utils/ssr.cjs.js +2 -0
- package/dist/utils/ssr.cjs.js.map +1 -0
- package/dist/utils/ssr.d.ts +35 -0
- package/dist/utils/ssr.d.ts.map +1 -0
- package/dist/utils/ssr.esm.js +48 -0
- package/dist/utils/ssr.esm.js.map +1 -0
- package/dist/vue.cjs.js +2 -0
- package/dist/vue.cjs.js.map +1 -0
- package/dist/vue.esm.js +10 -0
- package/dist/vue.esm.js.map +1 -0
- package/package.json +145 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatService.esm.js","sources":["../../src/services/chatService.ts"],"sourcesContent":["// services/chatService.ts\n\nimport { getSessionManager } from './sessionManager';\n\nexport interface SupportChatSession {\n chat_id: string;\n session_id: string;\n}\n\nexport interface SupportMessage {\n id?: string;\n sender_type: \"customer\" | \"agent\";\n content: string;\n timestamp: string;\n}\n\nexport interface ChatInfo {\n status: \"waiting\" | \"active\";\n agent_id?: string;\n}\n\nexport interface WebSocketMessage {\n type: \"message\" | \"chat_info\" | \"error\" | \"typing_start\" | \"typing_stop\" | \"agent_changed\" | \"agent_accepted\" | \"chat_resolved\" | \"chat_ended\" | \"ping\" | \"pong\";\n id?: string;\n chat_id?: string;\n sender_type?: \"customer\" | \"agent\";\n sender_id?: string;\n content?: string;\n timestamp?: string;\n status?: \"waiting\" | \"active\" | \"resolved\" | \"ended\";\n agent_id?: string;\n error?: string;\n from_agent?: string;\n to_agent?: string;\n to_agent_id?: string;\n reason?: string;\n message?: string;\n}\n\nexport class ChatResolvedError extends Error {\n reason = \"chat_resolved\" as const;\n constructor(message = \"chat_resolved\") {\n super(message);\n this.name = \"ChatResolvedError\";\n }\n}\n\nexport interface ChatServiceConfig {\n baseUrl?: string;\n wsUrl?: string;\n debug?: boolean;\n}\n\nexport interface StartSupportChatOptions {\n dialogflowSessionId?: string | null;\n customerName?: string | null;\n customerEmail?: string | null;\n customerMobile?: string | null;\n}\n\n// Get default URLs from environment variables or use fallbacks\n// Environment variables are injected at build time via webpack DefinePlugin\nconst DEFAULT_BASE_URL = \n (typeof process !== 'undefined' && (process as any).env?.REACT_APP_BACKEND_BASE_URL)\n \nconst DEFAULT_WS_URL = \n (typeof process !== 'undefined' && (process as any).env?.REACT_APP_BACKEND_WS_URL)\n\nclass ChatService {\n private baseUrl: string;\n private wsUrl: string;\n private debug: boolean;\n private ws: WebSocket | null = null;\n private wsReconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n private reconnectTimeout: NodeJS.Timeout | null = null;\n private pingInterval: NodeJS.Timeout | null = null;\n private currentChatId: string | null = null;\n private currentSessionId: string | null = null;\n private messageHandlers: Set<(message: WebSocketMessage) => void> = new Set();\n private connectionHandlers: Set<(connected: boolean) => void> = new Set();\n private sessionManager: ReturnType<typeof getSessionManager>;\n\n constructor(config: ChatServiceConfig = {}) {\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.wsUrl = config.wsUrl || DEFAULT_WS_URL;\n this.debug = config.debug || false;\n this.sessionManager = getSessionManager();\n }\n\n /**\n * Start a new support chat session\n * @param dialogflowSessionId - Optional: Dialogflow session ID\n * @param customerName - Optional: Customer name\n * @param customerEmail - Optional: Customer email\n * @param customerMobile - Optional: Customer mobile number\n */\n async startSupportChat(\n dialogflowSessionId?: string | null,\n customerName?: string | null,\n customerEmail?: string | null,\n customerMobile?: string | null\n ): Promise<SupportChatSession> {\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.sessionManager.getSessionHeader(),\n };\n\n if (dialogflowSessionId) {\n headers[\"X-Session-ID\"] = dialogflowSessionId;\n }\n\n const body: Record<string, any> = {};\n if (customerName) body.name = customerName;\n if (customerEmail) body.email = customerEmail;\n if (customerMobile) body.mobile = customerMobile;\n\n const response = await fetch(`${this.baseUrl}/api/support/chat/start`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = await response.json();\n this.sessionManager.updateSessionFromResponse(data);\n\n if (data.status && data.data) {\n return {\n chat_id: data.data.chat_id,\n session_id: data.data.session_id,\n };\n }\n\n if (data.chat_id && data.session_id) {\n return {\n chat_id: data.chat_id,\n session_id: data.session_id,\n };\n }\n\n throw new Error(\"Invalid response format from chat start endpoint\");\n } catch (error: any) {\n console.error(\"Error starting support chat:\", error);\n throw new Error(\n error.message || \"Failed to start support chat session\"\n );\n }\n }\n\n /**\n * Request handoff to human agent\n * @param chatId - Chat ID (must be valid, not undefined)\n * @param sessionId - Session ID\n * @param reason - Optional: Reason for handoff\n * @param dialogflowSessionId - Optional: Dialogflow session ID\n * @param customerName - Optional: Customer name\n * @param customerEmail - Optional: Customer email\n * @param customerMobile - Optional: Customer mobile number\n */\n async requestHandoff(\n chatId: string,\n sessionId: string,\n reason?: string,\n dialogflowSessionId?: string | null,\n customerName?: string | null,\n customerEmail?: string | null,\n customerMobile?: string | null\n ): Promise<{ success: boolean; message?: string }> {\n if (!chatId || chatId === \"undefined\" || chatId === \"null\") {\n throw new Error(\"Invalid chat_id. Chat must be initialized first.\");\n }\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.sessionManager.getSessionHeader(),\n };\n\n if (sessionId) {\n headers[\"X-Session-ID\"] = sessionId;\n } else if (dialogflowSessionId) {\n headers[\"X-Session-ID\"] = dialogflowSessionId;\n }\n\n const body: Record<string, any> = {};\n if (reason) body.reason = reason;\n if (customerName) body.name = customerName;\n if (customerEmail) body.email = customerEmail;\n if (customerMobile) body.mobile = customerMobile;\n\n const response = await fetch(\n `${this.baseUrl}/api/support/chat/${chatId}/handoff`,\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n }\n );\n\n if (response.status === 400 || response.status === 404) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || \"Invalid chat_id. Chat may have expired.\"\n );\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = await response.json();\n this.sessionManager.updateSessionFromResponse(data);\n\n if (data.status) {\n return {\n success: true,\n message: data.message || data.data?.message,\n };\n }\n\n return {\n success: true,\n message: data.message,\n };\n } catch (error: any) {\n console.error(\"Error requesting handoff:\", error);\n throw error;\n }\n }\n\n /**\n * Send message to agent via REST API\n */\n async sendMessageToAgent(\n chatId: string,\n sessionId: string,\n message: string\n ): Promise<SupportMessage> {\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.sessionManager.getSessionHeader(),\n };\n\n if (sessionId) {\n headers[\"X-Session-ID\"] = sessionId;\n }\n\n const response = await fetch(\n `${this.baseUrl}/api/support/chat/${chatId}/message`,\n {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n content: message,\n }),\n }\n );\n\n if (response.status === 401 || response.status === 404) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || \"Chat not found or unauthorized\"\n );\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = await response.json();\n this.sessionManager.updateSessionFromResponse(data);\n\n // Surface this explicitly so the UI can enter the terminal \"resolved\" state and avoid retries.\n if ((data as any)?.ignored === true && (data as any)?.reason === \"chat_resolved\") {\n throw new ChatResolvedError();\n }\n\n return {\n id: data.id,\n sender_type: \"customer\",\n content: message,\n timestamp: data.timestamp || new Date().toISOString(),\n };\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error.\n if (error instanceof ChatResolvedError || error?.name === \"ChatResolvedError\") {\n throw error;\n }\n console.error(\"Error sending message to agent:\", error);\n throw new Error(error.message || \"Failed to send message to agent\");\n }\n }\n\n /**\n * Ensure chat is initialized - helper method\n * Returns existing chat_id if valid, otherwise initializes new chat\n * @param existingChatId - Existing chat ID to validate\n * @param existingSessionId - Existing session ID\n * @param dialogflowSessionId - Optional: Dialogflow session ID\n * @param customerName - Optional: Customer name\n * @param customerEmail - Optional: Customer email\n * @param customerMobile - Optional: Customer mobile number\n * @returns Promise with chat_id and session_id\n */\n async ensureChatInitialized(\n existingChatId?: string | null,\n existingSessionId?: string | null,\n dialogflowSessionId?: string | null,\n customerName?: string | null,\n customerEmail?: string | null,\n customerMobile?: string | null\n ): Promise<SupportChatSession> {\n // Validate existing chat_id\n if (existingChatId && \n existingChatId !== \"undefined\" && \n existingChatId !== \"null\" &&\n existingSessionId) {\n return {\n chat_id: existingChatId,\n session_id: existingSessionId,\n };\n }\n\n // Initialize new chat\n return await this.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(\n chatId: string,\n sessionId: string\n ): Promise<SupportMessage[]> {\n try {\n const headers: Record<string, string> = {\n ...this.sessionManager.getSessionHeader(),\n };\n\n if (sessionId) {\n headers[\"X-Session-ID\"] = sessionId;\n }\n\n const response = await fetch(\n `${this.baseUrl}/api/support/chat/${chatId}/messages`,\n {\n method: \"GET\",\n headers,\n }\n );\n\n if (response.status === 401 || response.status === 404) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || \"Chat not found or unauthorized\"\n );\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(\n error.message || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = await response.json();\n this.sessionManager.updateSessionFromResponse(data);\n\n return data.messages || [];\n } catch (error: any) {\n console.error(\"Error loading message history:\", error);\n throw new Error(error.message || \"Failed to load message history\");\n }\n }\n\n /**\n * Connect to WebSocket\n */\n connectWebSocket(\n chatId: string,\n sessionId: string,\n onMessage?: (message: WebSocketMessage) => void,\n onConnectionChange?: (connected: boolean) => void,\n onClose?: (event: CloseEvent) => void\n ): void {\n // Clear any existing reconnection timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n if (this.debug) {\n console.log(\"WebSocket already connected\");\n }\n return;\n }\n\n // Store chatId and sessionId for reconnection\n this.currentChatId = chatId;\n this.currentSessionId = sessionId;\n\n // Add handlers\n if (onMessage) {\n this.messageHandlers.add(onMessage);\n }\n if (onConnectionChange) {\n this.connectionHandlers.add(onConnectionChange);\n }\n\n // CRITICAL: Get session_id from session manager (persisted from previous requests)\n // Use provided sessionId, or fallback to stored session, or empty string\n const sessionIdToUse = sessionId || this.sessionManager.getSessionId() || '';\n const wsUrl = `${this.wsUrl}/ws/support/${chatId}?X-Session-ID=${encodeURIComponent(sessionIdToUse)}`;\n\n try {\n this.ws = new WebSocket(wsUrl);\n\n this.ws.onopen = () => {\n if (this.debug) {\n console.log(\"WebSocket connected to:\", wsUrl);\n }\n console.log(\"✅ Customer WebSocket connected:\", { chatId, sessionId, wsUrl });\n this.wsReconnectAttempts = 0;\n this.connectionHandlers.forEach((handler) => handler(true));\n this.startPingInterval();\n };\n\n this.ws.onmessage = (event) => {\n try {\n const message: WebSocketMessage = JSON.parse(event.data);\n \n if (this.debug) {\n console.log(\"WebSocket raw message received:\", event.data);\n console.log(\"WebSocket parsed message:\", message);\n }\n \n // Update session_id from WebSocket messages if provided\n if ((message as any).session_id) {\n this.sessionManager.updateSessionFromResponse({ session_id: (message as any).session_id });\n }\n \n // Always log agent_accepted and chat_resolved messages for debugging\n if (message.type === \"agent_accepted\" || message.type === \"chat_resolved\" || message.type === \"chat_ended\") {\n console.log(\"🔔 Received notification message:\", {\n type: message.type,\n chat_id: message.chat_id,\n timestamp: message.timestamp,\n to_agent: (message as any).to_agent,\n to_agent_id: (message as any).to_agent_id\n });\n }\n \n // Handle pong messages silently (keep-alive response)\n if (message.type === \"pong\") {\n return;\n }\n \n // Log message type and sender info\n if (this.debug && message.type === \"message\") {\n console.log(\"Processing message type:\", {\n type: message.type,\n sender_type: message.sender_type,\n content: message.content?.substring(0, 50) + \"...\",\n id: message.id\n });\n }\n \n this.messageHandlers.forEach((handler) => handler(message));\n } catch (error) {\n console.error(\"Error parsing WebSocket message:\", error);\n if (this.debug) {\n console.error(\"Raw message data:\", event.data);\n }\n }\n };\n\n this.ws.onerror = (error) => {\n console.error(\"❌ WebSocket error:\", error);\n this.connectionHandlers.forEach((handler) => handler(false));\n };\n\n this.ws.onclose = (event) => {\n if (this.debug) {\n console.log(\"WebSocket closed:\", event.code, event.reason);\n }\n console.log(\"🔌 Customer WebSocket closed:\", { code: event.code, reason: event.reason, chatId });\n this.stopPingInterval();\n this.connectionHandlers.forEach((handler) => handler(false));\n this.ws = null;\n onClose?.(event);\n\n // Terminal close: backend uses 4000 to indicate chat was resolved.\n // Do NOT attempt to reconnect in this case.\n if (event.code === 4000) {\n this.wsReconnectAttempts = this.maxReconnectAttempts;\n this.currentChatId = null;\n this.currentSessionId = null;\n return;\n }\n\n // Attempt to reconnect with exponential backoff\n if (this.wsReconnectAttempts < this.maxReconnectAttempts && this.currentChatId && this.currentSessionId) {\n this.wsReconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.wsReconnectAttempts), 30000);\n if (this.debug) {\n console.log(`Reconnecting in ${delay}ms (attempt ${this.wsReconnectAttempts}/${this.maxReconnectAttempts})`);\n }\n \n this.reconnectTimeout = setTimeout(() => {\n if (this.currentChatId && this.currentSessionId) {\n this.connectWebSocket(this.currentChatId, this.currentSessionId, onMessage, onConnectionChange, onClose);\n }\n }, delay);\n } else if (this.debug) {\n console.error(\"Max reconnection attempts reached\");\n }\n };\n } catch (error) {\n console.error(\"Error creating WebSocket connection:\", error);\n this.connectionHandlers.forEach((handler) => handler(false));\n }\n }\n\n /**\n * Send message via WebSocket\n */\n sendMessageViaWebSocket(message: string): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n return false;\n }\n\n try {\n this.ws.send(\n JSON.stringify({\n type: \"message\",\n content: message,\n })\n );\n return true;\n } catch (error) {\n console.error(\"Error sending message via WebSocket:\", error);\n return false;\n }\n }\n\n /**\n * Send typing indicator via WebSocket\n */\n sendTypingIndicator(type: \"typing_start\" | \"typing_stop\"): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n return false;\n }\n\n try {\n this.ws.send(\n JSON.stringify({\n type: type,\n })\n );\n return true;\n } catch (error) {\n console.error(`Error sending ${type} via WebSocket:`, error);\n return false;\n }\n }\n\n /**\n * Start ping interval to keep connection alive\n */\n private startPingInterval(): void {\n this.stopPingInterval(); // Clear any existing interval\n this.pingInterval = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(JSON.stringify({ type: \"ping\" }));\n } catch (error) {\n console.error(\"Error sending ping:\", error);\n }\n }\n }, 30000); // Every 30 seconds\n }\n\n /**\n * Stop ping interval\n */\n private stopPingInterval(): void {\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n }\n\n /**\n * Disconnect WebSocket\n */\n disconnectWebSocket(): void {\n // Clear reconnection timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n \n // Stop ping interval\n this.stopPingInterval();\n \n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.messageHandlers.clear();\n this.connectionHandlers.clear();\n this.wsReconnectAttempts = 0;\n this.currentChatId = null;\n this.currentSessionId = null;\n }\n\n /**\n * Check if WebSocket is connected\n */\n isWebSocketConnected(): boolean {\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\n }\n\n /**\n * Remove message handler\n */\n removeMessageHandler(handler: (message: WebSocketMessage) => void): void {\n this.messageHandlers.delete(handler);\n }\n\n /**\n * Remove connection handler\n */\n removeConnectionHandler(handler: (connected: boolean) => void): void {\n this.connectionHandlers.delete(handler);\n }\n}\n\n// Export singleton instance\nlet chatServiceInstance: ChatService | null = null;\n\nexport function getChatService(config?: ChatServiceConfig): ChatService {\n if (!chatServiceInstance) {\n chatServiceInstance = new ChatService(config);\n }\n return chatServiceInstance;\n}\n\nexport function createChatService(config: ChatServiceConfig): ChatService {\n return new ChatService(config);\n}\n\n"],"names":[],"mappings":";AAuCO,MAAM,0BAA0B,MAAM;AAAA,EAE3C,YAAY,UAAU,iBAAiB;AACrC,UAAM,OAAO;AAFf,SAAA,SAAS;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAiBA,MAAM,mBACH,OAAO,YAAY,eAAgB,QAAgB,KAAK;AAE3D,MAAM,iBACH,OAAO,YAAY,eAAgB,QAAgB,KAAK;AAE3D,MAAM,YAAY;AAAA,EAehB,YAAY,SAA4B,IAAI;AAX5C,SAAQ,KAAuB;AAC/B,SAAQ,sBAAsB;AAC9B,SAAQ,uBAAuB;AAC/B,SAAQ,mBAA0C;AAClD,SAAQ,eAAsC;AAC9C,SAAQ,gBAA+B;AACvC,SAAQ,mBAAkC;AAC1C,SAAQ,sCAAgE,IAAA;AACxE,SAAQ,yCAA4D,IAAA;AAIlE,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,iBAAiB,kBAAA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBACJ,qBACA,cACA,eACA,gBAC6B;AAC7B,QAAI;AACF,YAAM,UAAkC;AAAA,QACtC,gBAAgB;AAAA,QAChB,GAAG,KAAK,eAAe,iBAAA;AAAA,MAAiB;AAG1C,UAAI,qBAAqB;AACvB,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,YAAM,OAA4B,CAAA;AAClC,UAAI,mBAAmB,OAAO;AAC9B,UAAI,oBAAoB,QAAQ;AAChC,UAAI,qBAAqB,SAAS;AAElC,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,2BAA2B;AAAA,QACrE,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAAA,CAC1B;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW,uBAAuB,SAAS,MAAM;AAAA,QAAA;AAAA,MAE3D;AAEA,YAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,WAAK,eAAe,0BAA0B,IAAI;AAElD,UAAI,KAAK,UAAU,KAAK,MAAM;AAC5B,eAAO;AAAA,UACL,SAAS,KAAK,KAAK;AAAA,UACnB,YAAY,KAAK,KAAK;AAAA,QAAA;AAAA,MAE1B;AAEA,UAAI,KAAK,WAAW,KAAK,YAAY;AACnC,eAAO;AAAA,UACL,SAAS,KAAK;AAAA,UACd,YAAY,KAAK;AAAA,QAAA;AAAA,MAErB;AAEA,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE,SAAS,OAAY;AACnB,cAAQ,MAAM,gCAAgC,KAAK;AACnD,YAAM,IAAI;AAAA,QACR,MAAM,WAAW;AAAA,MAAA;AAAA,IAErB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,eACJ,QACA,WACA,QACA,qBACA,cACA,eACA,gBACiD;AACjD,QAAI,CAAC,UAAU,WAAW,eAAe,WAAW,QAAQ;AAC1D,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AAEA,QAAI;AACF,YAAM,UAAkC;AAAA,QACtC,gBAAgB;AAAA,QAChB,GAAG,KAAK,eAAe,iBAAA;AAAA,MAAiB;AAG1C,UAAI,WAAW;AACb,gBAAQ,cAAc,IAAI;AAAA,MAC5B,WAAW,qBAAqB;AAC9B,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,YAAM,OAA4B,CAAA;AAClC,UAAI,aAAa,SAAS;AAC1B,UAAI,mBAAmB,OAAO;AAC9B,UAAI,oBAAoB,QAAQ;AAChC,UAAI,qBAAqB,SAAS;AAElC,YAAM,WAAW,MAAM;AAAA,QACrB,GAAG,KAAK,OAAO,qBAAqB,MAAM;AAAA,QAC1C;AAAA,UACE,QAAQ;AAAA,UACR;AAAA,UACA,MAAM,KAAK,UAAU,IAAI;AAAA,QAAA;AAAA,MAC3B;AAGF,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW;AAAA,QAAA;AAAA,MAErB;AAEA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW,uBAAuB,SAAS,MAAM;AAAA,QAAA;AAAA,MAE3D;AAEA,YAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,WAAK,eAAe,0BAA0B,IAAI;AAElD,UAAI,KAAK,QAAQ;AACf,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,KAAK,WAAW,KAAK,MAAM;AAAA,QAAA;AAAA,MAExC;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,KAAK;AAAA,MAAA;AAAA,IAElB,SAAS,OAAY;AACnB,cAAQ,MAAM,6BAA6B,KAAK;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBACJ,QACA,WACA,SACyB;AACzB,QAAI;AACF,YAAM,UAAkC;AAAA,QACtC,gBAAgB;AAAA,QAChB,GAAG,KAAK,eAAe,iBAAA;AAAA,MAAiB;AAG1C,UAAI,WAAW;AACb,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,YAAM,WAAW,MAAM;AAAA,QACrB,GAAG,KAAK,OAAO,qBAAqB,MAAM;AAAA,QAC1C;AAAA,UACE,QAAQ;AAAA,UACR;AAAA,UACA,MAAM,KAAK,UAAU;AAAA,YACnB,SAAS;AAAA,UAAA,CACV;AAAA,QAAA;AAAA,MACH;AAGF,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW;AAAA,QAAA;AAAA,MAErB;AAEA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW,uBAAuB,SAAS,MAAM;AAAA,QAAA;AAAA,MAE3D;AAEA,YAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,WAAK,eAAe,0BAA0B,IAAI;AAGlD,UAAK,MAAc,YAAY,QAAS,MAAc,WAAW,iBAAiB;AAChF,cAAM,IAAI,kBAAA;AAAA,MACZ;AAEA,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,QACT,WAAW,KAAK,cAAa,oBAAI,KAAA,GAAO,YAAA;AAAA,MAAY;AAAA,IAExD,SAAS,OAAY;AAEnB,UAAI,iBAAiB,qBAAqB,OAAO,SAAS,qBAAqB;AAC7E,cAAM;AAAA,MACR;AACA,cAAQ,MAAM,mCAAmC,KAAK;AACtD,YAAM,IAAI,MAAM,MAAM,WAAW,iCAAiC;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,sBACJ,gBACA,mBACA,qBACA,cACA,eACA,gBAC6B;AAE7B,QAAI,kBACA,mBAAmB,eACnB,mBAAmB,UACnB,mBAAmB;AACrB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,MAAA;AAAA,IAEhB;AAGA,WAAO,MAAM,KAAK;AAAA,MAChB,uBAAuB;AAAA,MACvB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,IAAA;AAAA,EAEtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBACJ,QACA,WAC2B;AAC3B,QAAI;AACF,YAAM,UAAkC;AAAA,QACtC,GAAG,KAAK,eAAe,iBAAA;AAAA,MAAiB;AAG1C,UAAI,WAAW;AACb,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,YAAM,WAAW,MAAM;AAAA,QACrB,GAAG,KAAK,OAAO,qBAAqB,MAAM;AAAA,QAC1C;AAAA,UACE,QAAQ;AAAA,UACR;AAAA,QAAA;AAAA,MACF;AAGF,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW;AAAA,QAAA;AAAA,MAErB;AAEA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,QAAQ,MAAM,SAAS,KAAA,EAAO,MAAM,OAAO,CAAA,EAAG;AACpD,cAAM,IAAI;AAAA,UACR,MAAM,WAAW,uBAAuB,SAAS,MAAM;AAAA,QAAA;AAAA,MAE3D;AAEA,YAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,WAAK,eAAe,0BAA0B,IAAI;AAElD,aAAO,KAAK,YAAY,CAAA;AAAA,IAC1B,SAAS,OAAY;AACnB,cAAQ,MAAM,kCAAkC,KAAK;AACrD,YAAM,IAAI,MAAM,MAAM,WAAW,gCAAgC;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBACE,QACA,WACA,WACA,oBACA,SACM;AAEN,QAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,gBAAgB;AAClC,WAAK,mBAAmB;AAAA,IAC1B;AAEA,QAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,MAAM;AACpD,UAAI,KAAK,OAAO;AACd,gBAAQ,IAAI,6BAA6B;AAAA,MAC3C;AACA;AAAA,IACF;AAGA,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AAGxB,QAAI,WAAW;AACb,WAAK,gBAAgB,IAAI,SAAS;AAAA,IACpC;AACA,QAAI,oBAAoB;AACtB,WAAK,mBAAmB,IAAI,kBAAkB;AAAA,IAChD;AAIA,UAAM,iBAAiB,aAAa,KAAK,eAAe,kBAAkB;AAC1E,UAAM,QAAQ,GAAG,KAAK,KAAK,eAAe,MAAM,iBAAiB,mBAAmB,cAAc,CAAC;AAEnG,QAAI;AACF,WAAK,KAAK,IAAI,UAAU,KAAK;AAE7B,WAAK,GAAG,SAAS,MAAM;AACrB,YAAI,KAAK,OAAO;AACd,kBAAQ,IAAI,2BAA2B,KAAK;AAAA,QAC9C;AACA,gBAAQ,IAAI,mCAAmC,EAAE,QAAQ,WAAW,OAAO;AAC3E,aAAK,sBAAsB;AAC3B,aAAK,mBAAmB,QAAQ,CAAC,YAAY,QAAQ,IAAI,CAAC;AAC1D,aAAK,kBAAA;AAAA,MACP;AAEA,WAAK,GAAG,YAAY,CAAC,UAAU;AAC7B,YAAI;AACF,gBAAM,UAA4B,KAAK,MAAM,MAAM,IAAI;AAEvD,cAAI,KAAK,OAAO;AACd,oBAAQ,IAAI,mCAAmC,MAAM,IAAI;AACzD,oBAAQ,IAAI,6BAA6B,OAAO;AAAA,UAClD;AAGA,cAAK,QAAgB,YAAY;AAC/B,iBAAK,eAAe,0BAA0B,EAAE,YAAa,QAAgB,YAAY;AAAA,UAC3F;AAGA,cAAI,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,mBAAmB,QAAQ,SAAS,cAAc;AAC1G,oBAAQ,IAAI,qCAAqC;AAAA,cAC/C,MAAM,QAAQ;AAAA,cACd,SAAS,QAAQ;AAAA,cACjB,WAAW,QAAQ;AAAA,cACnB,UAAW,QAAgB;AAAA,cAC3B,aAAc,QAAgB;AAAA,YAAA,CAC/B;AAAA,UACH;AAGA,cAAI,QAAQ,SAAS,QAAQ;AAC3B;AAAA,UACF;AAGA,cAAI,KAAK,SAAS,QAAQ,SAAS,WAAW;AAC5C,oBAAQ,IAAI,4BAA4B;AAAA,cACtC,MAAM,QAAQ;AAAA,cACd,aAAa,QAAQ;AAAA,cACrB,SAAS,QAAQ,SAAS,UAAU,GAAG,EAAE,IAAI;AAAA,cAC7C,IAAI,QAAQ;AAAA,YAAA,CACb;AAAA,UACH;AAEA,eAAK,gBAAgB,QAAQ,CAAC,YAAY,QAAQ,OAAO,CAAC;AAAA,QAC5D,SAAS,OAAO;AACd,kBAAQ,MAAM,oCAAoC,KAAK;AACvD,cAAI,KAAK,OAAO;AACd,oBAAQ,MAAM,qBAAqB,MAAM,IAAI;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAEA,WAAK,GAAG,UAAU,CAAC,UAAU;AAC3B,gBAAQ,MAAM,sBAAsB,KAAK;AACzC,aAAK,mBAAmB,QAAQ,CAAC,YAAY,QAAQ,KAAK,CAAC;AAAA,MAC7D;AAEA,WAAK,GAAG,UAAU,CAAC,UAAU;AAC3B,YAAI,KAAK,OAAO;AACd,kBAAQ,IAAI,qBAAqB,MAAM,MAAM,MAAM,MAAM;AAAA,QAC3D;AACA,gBAAQ,IAAI,iCAAiC,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,QAAQ,OAAA,CAAQ;AAC/F,aAAK,iBAAA;AACL,aAAK,mBAAmB,QAAQ,CAAC,YAAY,QAAQ,KAAK,CAAC;AAC3D,aAAK,KAAK;AACV,kBAAU,KAAK;AAIf,YAAI,MAAM,SAAS,KAAM;AACvB,eAAK,sBAAsB,KAAK;AAChC,eAAK,gBAAgB;AACrB,eAAK,mBAAmB;AACxB;AAAA,QACF;AAGA,YAAI,KAAK,sBAAsB,KAAK,wBAAwB,KAAK,iBAAiB,KAAK,kBAAkB;AACvG,eAAK;AACL,gBAAM,QAAQ,KAAK,IAAI,MAAO,KAAK,IAAI,GAAG,KAAK,mBAAmB,GAAG,GAAK;AAC1E,cAAI,KAAK,OAAO;AACd,oBAAQ,IAAI,mBAAmB,KAAK,eAAe,KAAK,mBAAmB,IAAI,KAAK,oBAAoB,GAAG;AAAA,UAC7G;AAEA,eAAK,mBAAmB,WAAW,MAAM;AACvC,gBAAI,KAAK,iBAAiB,KAAK,kBAAkB;AAC/C,mBAAK,iBAAiB,KAAK,eAAe,KAAK,kBAAkB,WAAW,oBAAoB,OAAO;AAAA,YACzG;AAAA,UACF,GAAG,KAAK;AAAA,QACV,WAAW,KAAK,OAAO;AACrB,kBAAQ,MAAM,mCAAmC;AAAA,QACnD;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,wCAAwC,KAAK;AAC3D,WAAK,mBAAmB,QAAQ,CAAC,YAAY,QAAQ,KAAK,CAAC;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,SAA0B;AAChD,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,MAAM;AACrD,aAAO;AAAA,IACT;AAEA,QAAI;AACF,WAAK,GAAG;AAAA,QACN,KAAK,UAAU;AAAA,UACb,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MAAA;AAEH,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,wCAAwC,KAAK;AAC3D,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,MAA+C;AACjE,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,MAAM;AACrD,aAAO;AAAA,IACT;AAEA,QAAI;AACF,WAAK,GAAG;AAAA,QACN,KAAK,UAAU;AAAA,UACb;AAAA,QAAA,CACD;AAAA,MAAA;AAEH,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,iBAAiB,IAAI,mBAAmB,KAAK;AAC3D,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA0B;AAChC,SAAK,iBAAA;AACL,SAAK,eAAe,YAAY,MAAM;AACpC,UAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,MAAM;AACpD,YAAI;AACF,eAAK,GAAG,KAAK,KAAK,UAAU,EAAE,MAAM,OAAA,CAAQ,CAAC;AAAA,QAC/C,SAAS,OAAO;AACd,kBAAQ,MAAM,uBAAuB,KAAK;AAAA,QAC5C;AAAA,MACF;AAAA,IACF,GAAG,GAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,QAAI,KAAK,cAAc;AACrB,oBAAc,KAAK,YAAY;AAC/B,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA4B;AAE1B,QAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,gBAAgB;AAClC,WAAK,mBAAmB;AAAA,IAC1B;AAGA,SAAK,iBAAA;AAEL,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAA;AACR,WAAK,KAAK;AAAA,IACZ;AACA,SAAK,gBAAgB,MAAA;AACrB,SAAK,mBAAmB,MAAA;AACxB,SAAK,sBAAsB;AAC3B,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAgC;AAC9B,WAAO,KAAK,OAAO,QAAQ,KAAK,GAAG,eAAe,UAAU;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,SAAoD;AACvE,SAAK,gBAAgB,OAAO,OAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,SAA6C;AACnE,SAAK,mBAAmB,OAAO,OAAO;AAAA,EACxC;AACF;AAYO,SAAS,kBAAkB,QAAwC;AACxE,SAAO,IAAI,YAAY,MAAM;AAC/B;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../node_modules/jose/dist/browser/key/import.cjs.js"),t=require("../node_modules/jose/dist/browser/jwt/sign.cjs.js");async function o(o){if(o.accessToken)return o.accessToken;if(!o.serviceAccountKey)throw new Error("Either serviceAccountKey or accessToken must be provided");return await async function(o){const s=Math.floor(Date.now()/1e3);let r=o.private_key;if(!r)throw new Error("Private key is missing from service account key");if(r=r.trim(),r.includes("-----BEGIN")){if(r=r.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),r.includes("BEGIN RSA PRIVATE KEY"))throw new Error("Private key is in PKCS#1 format (RSA PRIVATE KEY). Please download a new service account key from Google Cloud Console. The key should be in PKCS#8 format (PRIVATE KEY).");const e=r.match(/-----BEGIN PRIVATE KEY-----\n?([\s\S]*?)\n?-----END PRIVATE KEY-----/);if(e){const t=e[1].replace(/\s/g,"");(!t.includes("\n")||t.length>64)&&(r=`-----BEGIN PRIVATE KEY-----\n${t.match(/.{1,64}/g)?.join("\n")||t}\n-----END PRIVATE KEY-----`)}}else{const e=r.replace(/\s/g,"");r=`-----BEGIN PRIVATE KEY-----\n${e.match(/.{1,64}/g)?.join("\n")||e}\n-----END PRIVATE KEY-----`}try{const n=await e.importPKCS8(r,"RS256"),a=await new t.SignJWT({scope:"https://www.googleapis.com/auth/cloud-platform"}).setProtectedHeader({alg:"RS256"}).setIssuedAt(s).setExpirationTime(s+3600).setIssuer(o.client_email).setSubject(o.client_email).setAudience("https://oauth2.googleapis.com/token").sign(n),i=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:a})});if(!i.ok){const e=await i.json();throw new Error(e.error_description||"Failed to get access token")}return(await i.json()).access_token}catch(n){if(n.message&&n.message.includes("pkcs8"))throw new Error("Invalid private key format. The service account key must be in PKCS#8 format. Please ensure your service account key JSON file has a properly formatted private_key field. If you downloaded the key from Google Cloud Console, it should already be in the correct format.");throw n}}(o.serviceAccountKey)}function s(e,t,o,s){return`projects/${e}/locations/${t}/agents/${o}/sessions/${s}`}function r(e){let t=null;for(const o of e)if(o.payload){if(o.payload.richContent){t=o.payload.richContent;break}if(o.payload.fields&&o.payload.fields.richContent){const e=o.payload.fields.richContent;e.listValue&&e.listValue.values?t=e.listValue.values.map(e=>e.listValue&&e.listValue.values?e.listValue.values.map(e=>{if(e.structValue&&e.structValue.fields){const t=e.structValue.fields;if(t.type&&t.options)return{type:t.type.stringValue||t.type,options:t.options.listValue?t.options.listValue.values.map(e=>({text:e.structValue?.fields?.text?.stringValue||"",payload:e.structValue?.fields?.payload?.stringValue||""})):[]}}return e}):e):"object"!=typeof e||e.listValue||(t=e);break}}return t}exports.createDialogflowSession=async function(e){try{const t=await o(e),n=`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a=e.dfLocation.split(" ")[0].trim(),i=`https://${a}-dialogflow.googleapis.com/v3/${s(e.dfProjectId,a,e.dfAgentId,n)}:detectIntent`,l={queryInput:{text:{text:"hello"},languageCode:e.languageCode||"en"}},c=await fetch(i,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(l)});if(!c.ok){const e=await c.json().catch(()=>({}));throw new Error(e.error?.message||`HTTP error! status: ${c.status}`)}const u=await c.json();let d="Hello! I'm BlockSpark AI Assistant. How can I help you today?",f=null;if(u.queryResult?.responseMessages){const e=u.queryResult.responseMessages.filter(e=>e.text).map(e=>e.text.text.join(" "));e.length>0&&(d=e.join(" ")),f=r(u.queryResult.responseMessages)}else u.queryResult?.fulfillmentText&&(d=u.queryResult.fulfillmentText);return{session_id:n,message:d,...f&&{richContent:f}}}catch(t){const e=t.message||"Failed to create session";if(e.includes("401")||e.includes("Unauthorized"))throw new Error("Authentication failed. Please check your service account key or access token.");if(e.includes("403")||e.includes("Forbidden"))throw new Error("Access forbidden. Please check your Dialogflow API permissions.");if(e.includes("404")||e.includes("Not Found"))throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");throw new Error(e)}},exports.sendDialogflowMessage=async function(e,t,n){try{const a=await o(n),i=n.dfLocation.split(" ")[0].trim(),l=`https://${i}-dialogflow.googleapis.com/v3/${s(n.dfProjectId,i,n.dfAgentId,t)}:detectIntent`,c={queryInput:{text:{text:e.trim()},languageCode:n.languageCode||"en"}},u=await fetch(l,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},body:JSON.stringify(c)});if(!u.ok){const e=await u.text();let t={};try{t=JSON.parse(e)}catch{t={message:e||`HTTP ${u.status}`}}const o=t.error?.message||t.message||`HTTP error! status: ${u.status}`;throw new Error(o)}const d=await u.json();let f="I'm sorry, I didn't understand that. Could you please rephrase?",p=null,y=!1;if(!0===d.queryResult?.parameters?.fields?.handoff?.boolValue)y=!0;else if(d.queryResult?.responseMessages)for(const e of d.queryResult.responseMessages)if(e.payload&&"object"==typeof e.payload){if(!0===e.payload.handoff){y=!0;break}if(!0===e.payload.fields?.handoff?.boolValue){y=!0;break}}if(!0===d.handoff&&(y=!0),d.queryResult?.responseMessages){const e=d.queryResult.responseMessages.filter(e=>e.text).map(e=>e.text.text.join(" "));e.length>0&&(f=e.join(" ")),p=r(d.queryResult.responseMessages)}else d.queryResult?.fulfillmentText&&(f=d.queryResult.fulfillmentText);return{response:f,session_id:t,source:"dialogflow",timestamp:(new Date).toISOString(),...p&&{richContent:p},...y&&{handoff:!0}}}catch(a){const e=a.message||"Failed to send message";if(e.includes("401")||e.includes("Unauthorized"))throw new Error("Authentication failed. Please check your service account key or access token.");if(e.includes("403")||e.includes("Forbidden"))throw new Error("Access forbidden. Please check your Dialogflow API permissions.");if(e.includes("404")||e.includes("Not Found"))throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");if(e.includes("CORS"))throw new Error("CORS error. Dialogflow API may not allow browser requests. Consider using a backend proxy.");throw new Error(e)}};
|
|
2
|
+
//# sourceMappingURL=dialogflowClient.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogflowClient.cjs.js","sources":["../../src/services/dialogflowClient.ts"],"sourcesContent":["// services/dialogflowClient.ts\nimport { SignJWT, importPKCS8 } from 'jose';\n\nexport interface DialogflowConfig {\n dfProjectId: string;\n dfLocation: string;\n dfAgentId: string;\n serviceAccountKey?: any; // Service account JSON object\n accessToken?: string; // Alternative: provide access token directly\n languageCode?: string;\n}\n\nexport interface SessionResponse {\n session_id: string;\n message: string;\n richContent?: any;\n}\n\nexport interface ChatResponse {\n response: string;\n session_id: string;\n source: string;\n timestamp: string;\n richContent?: any;\n handoff?: boolean;\n}\n\n// Helper to get access token from service account using Web Crypto API\nasync function getAccessTokenFromServiceAccount(serviceAccountKey: any): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n \n // Format the private key - ensure it's properly formatted for PKCS#8\n let privateKeyPem = serviceAccountKey.private_key;\n \n // Google service account keys should already be in PKCS#8 format\n // But we need to ensure proper formatting with newlines\n if (privateKeyPem) {\n // Remove any existing whitespace/newlines\n privateKeyPem = privateKeyPem.trim();\n \n // If it doesn't have headers, it's just the base64 content\n if (!privateKeyPem.includes('-----BEGIN')) {\n // Wrap the base64 content with proper headers\n // Split into 64-character lines for proper PEM format\n const keyContent = privateKeyPem.replace(/\\s/g, '');\n const formattedKey = keyContent.match(/.{1,64}/g)?.join('\\n') || keyContent;\n privateKeyPem = `-----BEGIN PRIVATE KEY-----\\n${formattedKey}\\n-----END PRIVATE KEY-----`;\n } else {\n // Key has headers, but ensure proper line breaks\n // Normalize line breaks to \\n\n privateKeyPem = privateKeyPem.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n \n // If it's RSA PRIVATE KEY (PKCS#1), we need to note that jose can't convert it\n // Google service accounts should provide PKCS#8, but if not, we'll try to use as-is\n if (privateKeyPem.includes('BEGIN RSA PRIVATE KEY')) {\n throw new Error(\n 'Private key is in PKCS#1 format (RSA PRIVATE KEY). ' +\n 'Please download a new service account key from Google Cloud Console. ' +\n 'The key should be in PKCS#8 format (PRIVATE KEY).'\n );\n }\n \n // Ensure the key content is properly formatted (64 chars per line)\n const keyMatch = privateKeyPem.match(/-----BEGIN PRIVATE KEY-----\\n?([\\s\\S]*?)\\n?-----END PRIVATE KEY-----/);\n if (keyMatch) {\n const keyContent = keyMatch[1].replace(/\\s/g, '');\n // Check if already properly formatted (has newlines every 64 chars)\n if (!keyContent.includes('\\n') || keyContent.length > 64) {\n const formattedKey = keyContent.match(/.{1,64}/g)?.join('\\n') || keyContent;\n privateKeyPem = `-----BEGIN PRIVATE KEY-----\\n${formattedKey}\\n-----END PRIVATE KEY-----`;\n }\n }\n }\n } else {\n throw new Error('Private key is missing from service account key');\n }\n \n try {\n // Import the private key (jose expects PKCS#8 format)\n const privateKey = await importPKCS8(privateKeyPem, 'RS256');\n \n // Create JWT\n const jwt = await new SignJWT({\n scope: 'https://www.googleapis.com/auth/cloud-platform',\n })\n .setProtectedHeader({ alg: 'RS256' })\n .setIssuedAt(now)\n .setExpirationTime(now + 3600)\n .setIssuer(serviceAccountKey.client_email)\n .setSubject(serviceAccountKey.client_email)\n .setAudience('https://oauth2.googleapis.com/token')\n .sign(privateKey);\n\n // Exchange JWT for access token\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Failed to get access token');\n }\n\n const data = await response.json();\n return data.access_token;\n } catch (error: any) {\n if (error.message && error.message.includes('pkcs8')) {\n throw new Error(\n 'Invalid private key format. The service account key must be in PKCS#8 format. ' +\n 'Please ensure your service account key JSON file has a properly formatted private_key field. ' +\n 'If you downloaded the key from Google Cloud Console, it should already be in the correct format.'\n );\n }\n throw error;\n }\n}\n\n// Get access token (either from service account or use provided token)\nasync function getAccessToken(config: DialogflowConfig): Promise<string> {\n if (config.accessToken) {\n return config.accessToken;\n }\n \n if (!config.serviceAccountKey) {\n throw new Error('Either serviceAccountKey or accessToken must be provided');\n }\n\n return await getAccessTokenFromServiceAccount(config.serviceAccountKey);\n}\n\n// Create session path\nfunction createSessionPath(projectId: string, location: string, agentId: string, sessionId: string): string {\n return `projects/${projectId}/locations/${location}/agents/${agentId}/sessions/${sessionId}`;\n}\n\n// Extract rich content from Dialogflow response\nfunction extractRichContent(responseMessages: any[]): any {\n let richContent = null;\n \n for (const msg of responseMessages) {\n if (msg.payload) {\n if (msg.payload.richContent) {\n richContent = msg.payload.richContent;\n break;\n }\n if (msg.payload.fields && msg.payload.fields.richContent) {\n const richContentValue = msg.payload.fields.richContent;\n if (richContentValue.listValue && richContentValue.listValue.values) {\n richContent = richContentValue.listValue.values.map((v: any) => {\n if (v.listValue && v.listValue.values) {\n return v.listValue.values.map((item: any) => {\n if (item.structValue && item.structValue.fields) {\n const fields = item.structValue.fields;\n if (fields.type && fields.options) {\n return {\n type: fields.type.stringValue || fields.type,\n options: fields.options.listValue\n ? fields.options.listValue.values.map((opt: any) => ({\n text: opt.structValue?.fields?.text?.stringValue || '',\n payload: opt.structValue?.fields?.payload?.stringValue || '',\n }))\n : [],\n };\n }\n }\n return item;\n });\n }\n return v;\n });\n } else if (typeof richContentValue === 'object' && !richContentValue.listValue) {\n richContent = richContentValue;\n }\n break;\n }\n }\n }\n \n return richContent;\n}\n\n/**\n * Create a new Dialogflow session\n * @param config - Dialogflow configuration\n * @returns Promise with session ID and welcome message\n */\nexport async function createDialogflowSession(config: DialogflowConfig): Promise<SessionResponse> {\n try {\n const accessToken = await getAccessToken(config);\n const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const location = config.dfLocation.split(' ')[0].trim(); // Extract just the location code\n const sessionPath = createSessionPath(\n config.dfProjectId,\n location,\n config.dfAgentId,\n sessionId\n );\n\n const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;\n\n // Get welcome message\n const request = {\n queryInput: {\n text: {\n text: 'hello',\n },\n languageCode: config.languageCode || 'en',\n },\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n \n let welcomeMessage = \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\";\n let richContent = null;\n\n if (data.queryResult?.responseMessages) {\n const textMessages = data.queryResult.responseMessages\n .filter((msg: any) => msg.text)\n .map((msg: any) => msg.text.text.join(' '));\n \n if (textMessages.length > 0) {\n welcomeMessage = textMessages.join(' ');\n }\n\n richContent = extractRichContent(data.queryResult.responseMessages);\n } else if (data.queryResult?.fulfillmentText) {\n welcomeMessage = data.queryResult.fulfillmentText;\n }\n\n return {\n session_id: sessionId,\n message: welcomeMessage,\n ...(richContent && { richContent }),\n };\n } catch (error: any) {\n console.error('Error creating Dialogflow session:', error);\n const errorMessage = error.message || 'Failed to create session';\n if (errorMessage.includes('401') || errorMessage.includes('Unauthorized')) {\n throw new Error('Authentication failed. Please check your service account key or access token.');\n } else if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {\n throw new Error('Access forbidden. Please check your Dialogflow API permissions.');\n } else if (errorMessage.includes('404') || errorMessage.includes('Not Found')) {\n throw new Error('Dialogflow agent not found. Please check your project ID, location, and agent ID.');\n }\n throw new Error(errorMessage);\n }\n}\n\n/**\n * Send a message to Dialogflow\n * @param message - The user's message\n * @param sessionId - The session ID\n * @param config - Dialogflow configuration\n * @returns Promise with bot response\n */\nexport async function sendDialogflowMessage(\n message: string,\n sessionId: string,\n config: DialogflowConfig\n): Promise<ChatResponse> {\n try {\n const accessToken = await getAccessToken(config);\n const location = config.dfLocation.split(' ')[0].trim(); // Extract just the location code\n const sessionPath = createSessionPath(\n config.dfProjectId,\n location,\n config.dfAgentId,\n sessionId\n );\n\n const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;\n\n const request = {\n queryInput: {\n text: {\n text: message.trim(),\n },\n languageCode: config.languageCode || 'en',\n },\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorData: any = {};\n try {\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { message: errorText || `HTTP ${response.status}` };\n }\n const errorMessage = errorData.error?.message || errorData.message || `HTTP error! status: ${response.status}`;\n console.error('Dialogflow API Error (sendMessage):', {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n endpoint: apiEndpoint,\n });\n throw new Error(errorMessage);\n }\n\n const data = await response.json();\n\n let responseText = \"I'm sorry, I didn't understand that. Could you please rephrase?\";\n let richContent = null;\n let handoff = false;\n\n // Check for handoff trigger\n if (data.queryResult?.parameters?.fields?.handoff?.boolValue === true) {\n handoff = true;\n } else if (data.queryResult?.responseMessages) {\n // Check in responseMessages payload\n for (const msg of data.queryResult.responseMessages) {\n if (msg.payload) {\n if (typeof msg.payload === 'object') {\n if (msg.payload.handoff === true) {\n handoff = true;\n break;\n }\n if (msg.payload.fields?.handoff?.boolValue === true) {\n handoff = true;\n break;\n }\n }\n }\n }\n }\n \n // Check at root level\n if (data.handoff === true) {\n handoff = true;\n }\n\n if (data.queryResult?.responseMessages) {\n const textMessages = data.queryResult.responseMessages\n .filter((msg: any) => msg.text)\n .map((msg: any) => msg.text.text.join(' '));\n \n if (textMessages.length > 0) {\n responseText = textMessages.join(' ');\n }\n\n richContent = extractRichContent(data.queryResult.responseMessages);\n } else if (data.queryResult?.fulfillmentText) {\n responseText = data.queryResult.fulfillmentText;\n }\n\n return {\n response: responseText,\n session_id: sessionId,\n source: 'dialogflow',\n timestamp: new Date().toISOString(),\n ...(richContent && { richContent }),\n ...(handoff && { handoff: true }),\n };\n } catch (error: any) {\n console.error('Error sending message to Dialogflow:', error);\n const errorMessage = error.message || 'Failed to send message';\n if (errorMessage.includes('401') || errorMessage.includes('Unauthorized')) {\n throw new Error('Authentication failed. Please check your service account key or access token.');\n } else if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {\n throw new Error('Access forbidden. Please check your Dialogflow API permissions.');\n } else if (errorMessage.includes('404') || errorMessage.includes('Not Found')) {\n throw new Error('Dialogflow agent not found. Please check your project ID, location, and agent ID.');\n } else if (errorMessage.includes('CORS')) {\n throw new Error('CORS error. Dialogflow API may not allow browser requests. Consider using a backend proxy.');\n }\n throw new Error(errorMessage);\n }\n}\n\n"],"names":["async","getAccessToken","config","accessToken","serviceAccountKey","Error","now","Math","floor","Date","privateKeyPem","private_key","trim","includes","replace","keyMatch","match","keyContent","length","join","privateKey","importPKCS8","jwt","SignJWT","scope","setProtectedHeader","alg","setIssuedAt","setExpirationTime","setIssuer","client_email","setSubject","setAudience","sign","response","fetch","method","headers","body","URLSearchParams","grant_type","assertion","ok","error","json","error_description","access_token","message","getAccessTokenFromServiceAccount","createSessionPath","projectId","location","agentId","sessionId","extractRichContent","responseMessages","richContent","msg","payload","fields","richContentValue","listValue","values","map","v","item","structValue","type","options","stringValue","opt","text","random","toString","substr","dfLocation","split","apiEndpoint","dfProjectId","dfAgentId","request","queryInput","languageCode","Authorization","JSON","stringify","catch","status","data","welcomeMessage","queryResult","textMessages","filter","fulfillmentText","session_id","errorMessage","errorText","errorData","parse","responseText","handoff","parameters","boolValue","source","timestamp","toISOString"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface DialogflowConfig {
|
|
2
|
+
dfProjectId: string;
|
|
3
|
+
dfLocation: string;
|
|
4
|
+
dfAgentId: string;
|
|
5
|
+
serviceAccountKey?: any;
|
|
6
|
+
accessToken?: string;
|
|
7
|
+
languageCode?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SessionResponse {
|
|
10
|
+
session_id: string;
|
|
11
|
+
message: string;
|
|
12
|
+
richContent?: any;
|
|
13
|
+
}
|
|
14
|
+
export interface ChatResponse {
|
|
15
|
+
response: string;
|
|
16
|
+
session_id: string;
|
|
17
|
+
source: string;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
richContent?: any;
|
|
20
|
+
handoff?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new Dialogflow session
|
|
24
|
+
* @param config - Dialogflow configuration
|
|
25
|
+
* @returns Promise with session ID and welcome message
|
|
26
|
+
*/
|
|
27
|
+
export declare function createDialogflowSession(config: DialogflowConfig): Promise<SessionResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Send a message to Dialogflow
|
|
30
|
+
* @param message - The user's message
|
|
31
|
+
* @param sessionId - The session ID
|
|
32
|
+
* @param config - Dialogflow configuration
|
|
33
|
+
* @returns Promise with bot response
|
|
34
|
+
*/
|
|
35
|
+
export declare function sendDialogflowMessage(message: string, sessionId: string, config: DialogflowConfig): Promise<ChatResponse>;
|
|
36
|
+
//# sourceMappingURL=dialogflowClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogflowClient.d.ts","sourceRoot":"","sources":["../../src/services/dialogflowClient.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,GAAG,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiKD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0EhG;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,YAAY,CAAC,CAqHvB"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { importPKCS8 } from "../node_modules/jose/dist/browser/key/import.esm.js";
|
|
2
|
+
import { SignJWT } from "../node_modules/jose/dist/browser/jwt/sign.esm.js";
|
|
3
|
+
async function getAccessTokenFromServiceAccount(serviceAccountKey) {
|
|
4
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
5
|
+
let privateKeyPem = serviceAccountKey.private_key;
|
|
6
|
+
if (privateKeyPem) {
|
|
7
|
+
privateKeyPem = privateKeyPem.trim();
|
|
8
|
+
if (!privateKeyPem.includes("-----BEGIN")) {
|
|
9
|
+
const keyContent = privateKeyPem.replace(/\s/g, "");
|
|
10
|
+
const formattedKey = keyContent.match(/.{1,64}/g)?.join("\n") || keyContent;
|
|
11
|
+
privateKeyPem = `-----BEGIN PRIVATE KEY-----
|
|
12
|
+
${formattedKey}
|
|
13
|
+
-----END PRIVATE KEY-----`;
|
|
14
|
+
} else {
|
|
15
|
+
privateKeyPem = privateKeyPem.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
16
|
+
if (privateKeyPem.includes("BEGIN RSA PRIVATE KEY")) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Private key is in PKCS#1 format (RSA PRIVATE KEY). Please download a new service account key from Google Cloud Console. The key should be in PKCS#8 format (PRIVATE KEY)."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
const keyMatch = privateKeyPem.match(/-----BEGIN PRIVATE KEY-----\n?([\s\S]*?)\n?-----END PRIVATE KEY-----/);
|
|
22
|
+
if (keyMatch) {
|
|
23
|
+
const keyContent = keyMatch[1].replace(/\s/g, "");
|
|
24
|
+
if (!keyContent.includes("\n") || keyContent.length > 64) {
|
|
25
|
+
const formattedKey = keyContent.match(/.{1,64}/g)?.join("\n") || keyContent;
|
|
26
|
+
privateKeyPem = `-----BEGIN PRIVATE KEY-----
|
|
27
|
+
${formattedKey}
|
|
28
|
+
-----END PRIVATE KEY-----`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error("Private key is missing from service account key");
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const privateKey = await importPKCS8(privateKeyPem, "RS256");
|
|
37
|
+
const jwt = await new SignJWT({
|
|
38
|
+
scope: "https://www.googleapis.com/auth/cloud-platform"
|
|
39
|
+
}).setProtectedHeader({ alg: "RS256" }).setIssuedAt(now).setExpirationTime(now + 3600).setIssuer(serviceAccountKey.client_email).setSubject(serviceAccountKey.client_email).setAudience("https://oauth2.googleapis.com/token").sign(privateKey);
|
|
40
|
+
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
43
|
+
body: new URLSearchParams({
|
|
44
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
45
|
+
assertion: jwt
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const error = await response.json();
|
|
50
|
+
throw new Error(error.error_description || "Failed to get access token");
|
|
51
|
+
}
|
|
52
|
+
const data = await response.json();
|
|
53
|
+
return data.access_token;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error.message && error.message.includes("pkcs8")) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
"Invalid private key format. The service account key must be in PKCS#8 format. Please ensure your service account key JSON file has a properly formatted private_key field. If you downloaded the key from Google Cloud Console, it should already be in the correct format."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function getAccessToken(config) {
|
|
64
|
+
if (config.accessToken) {
|
|
65
|
+
return config.accessToken;
|
|
66
|
+
}
|
|
67
|
+
if (!config.serviceAccountKey) {
|
|
68
|
+
throw new Error("Either serviceAccountKey or accessToken must be provided");
|
|
69
|
+
}
|
|
70
|
+
return await getAccessTokenFromServiceAccount(config.serviceAccountKey);
|
|
71
|
+
}
|
|
72
|
+
function createSessionPath(projectId, location, agentId, sessionId) {
|
|
73
|
+
return `projects/${projectId}/locations/${location}/agents/${agentId}/sessions/${sessionId}`;
|
|
74
|
+
}
|
|
75
|
+
function extractRichContent(responseMessages) {
|
|
76
|
+
let richContent = null;
|
|
77
|
+
for (const msg of responseMessages) {
|
|
78
|
+
if (msg.payload) {
|
|
79
|
+
if (msg.payload.richContent) {
|
|
80
|
+
richContent = msg.payload.richContent;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (msg.payload.fields && msg.payload.fields.richContent) {
|
|
84
|
+
const richContentValue = msg.payload.fields.richContent;
|
|
85
|
+
if (richContentValue.listValue && richContentValue.listValue.values) {
|
|
86
|
+
richContent = richContentValue.listValue.values.map((v) => {
|
|
87
|
+
if (v.listValue && v.listValue.values) {
|
|
88
|
+
return v.listValue.values.map((item) => {
|
|
89
|
+
if (item.structValue && item.structValue.fields) {
|
|
90
|
+
const fields = item.structValue.fields;
|
|
91
|
+
if (fields.type && fields.options) {
|
|
92
|
+
return {
|
|
93
|
+
type: fields.type.stringValue || fields.type,
|
|
94
|
+
options: fields.options.listValue ? fields.options.listValue.values.map((opt) => ({
|
|
95
|
+
text: opt.structValue?.fields?.text?.stringValue || "",
|
|
96
|
+
payload: opt.structValue?.fields?.payload?.stringValue || ""
|
|
97
|
+
})) : []
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return item;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return v;
|
|
105
|
+
});
|
|
106
|
+
} else if (typeof richContentValue === "object" && !richContentValue.listValue) {
|
|
107
|
+
richContent = richContentValue;
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return richContent;
|
|
114
|
+
}
|
|
115
|
+
async function createDialogflowSession(config) {
|
|
116
|
+
try {
|
|
117
|
+
const accessToken = await getAccessToken(config);
|
|
118
|
+
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
119
|
+
const location = config.dfLocation.split(" ")[0].trim();
|
|
120
|
+
const sessionPath = createSessionPath(
|
|
121
|
+
config.dfProjectId,
|
|
122
|
+
location,
|
|
123
|
+
config.dfAgentId,
|
|
124
|
+
sessionId
|
|
125
|
+
);
|
|
126
|
+
const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;
|
|
127
|
+
const request = {
|
|
128
|
+
queryInput: {
|
|
129
|
+
text: {
|
|
130
|
+
text: "hello"
|
|
131
|
+
},
|
|
132
|
+
languageCode: config.languageCode || "en"
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const response = await fetch(apiEndpoint, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: {
|
|
138
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
139
|
+
"Content-Type": "application/json"
|
|
140
|
+
},
|
|
141
|
+
body: JSON.stringify(request)
|
|
142
|
+
});
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
const error = await response.json().catch(() => ({}));
|
|
145
|
+
throw new Error(error.error?.message || `HTTP error! status: ${response.status}`);
|
|
146
|
+
}
|
|
147
|
+
const data = await response.json();
|
|
148
|
+
let welcomeMessage = "Hello! I'm BlockSpark AI Assistant. How can I help you today?";
|
|
149
|
+
let richContent = null;
|
|
150
|
+
if (data.queryResult?.responseMessages) {
|
|
151
|
+
const textMessages = data.queryResult.responseMessages.filter((msg) => msg.text).map((msg) => msg.text.text.join(" "));
|
|
152
|
+
if (textMessages.length > 0) {
|
|
153
|
+
welcomeMessage = textMessages.join(" ");
|
|
154
|
+
}
|
|
155
|
+
richContent = extractRichContent(data.queryResult.responseMessages);
|
|
156
|
+
} else if (data.queryResult?.fulfillmentText) {
|
|
157
|
+
welcomeMessage = data.queryResult.fulfillmentText;
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
session_id: sessionId,
|
|
161
|
+
message: welcomeMessage,
|
|
162
|
+
...richContent && { richContent }
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error("Error creating Dialogflow session:", error);
|
|
166
|
+
const errorMessage = error.message || "Failed to create session";
|
|
167
|
+
if (errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
|
|
168
|
+
throw new Error("Authentication failed. Please check your service account key or access token.");
|
|
169
|
+
} else if (errorMessage.includes("403") || errorMessage.includes("Forbidden")) {
|
|
170
|
+
throw new Error("Access forbidden. Please check your Dialogflow API permissions.");
|
|
171
|
+
} else if (errorMessage.includes("404") || errorMessage.includes("Not Found")) {
|
|
172
|
+
throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");
|
|
173
|
+
}
|
|
174
|
+
throw new Error(errorMessage);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function sendDialogflowMessage(message, sessionId, config) {
|
|
178
|
+
try {
|
|
179
|
+
const accessToken = await getAccessToken(config);
|
|
180
|
+
const location = config.dfLocation.split(" ")[0].trim();
|
|
181
|
+
const sessionPath = createSessionPath(
|
|
182
|
+
config.dfProjectId,
|
|
183
|
+
location,
|
|
184
|
+
config.dfAgentId,
|
|
185
|
+
sessionId
|
|
186
|
+
);
|
|
187
|
+
const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;
|
|
188
|
+
const request = {
|
|
189
|
+
queryInput: {
|
|
190
|
+
text: {
|
|
191
|
+
text: message.trim()
|
|
192
|
+
},
|
|
193
|
+
languageCode: config.languageCode || "en"
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const response = await fetch(apiEndpoint, {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: {
|
|
199
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
200
|
+
"Content-Type": "application/json"
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify(request)
|
|
203
|
+
});
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
const errorText = await response.text();
|
|
206
|
+
let errorData = {};
|
|
207
|
+
try {
|
|
208
|
+
errorData = JSON.parse(errorText);
|
|
209
|
+
} catch {
|
|
210
|
+
errorData = { message: errorText || `HTTP ${response.status}` };
|
|
211
|
+
}
|
|
212
|
+
const errorMessage = errorData.error?.message || errorData.message || `HTTP error! status: ${response.status}`;
|
|
213
|
+
console.error("Dialogflow API Error (sendMessage):", {
|
|
214
|
+
status: response.status,
|
|
215
|
+
statusText: response.statusText,
|
|
216
|
+
error: errorData,
|
|
217
|
+
endpoint: apiEndpoint
|
|
218
|
+
});
|
|
219
|
+
throw new Error(errorMessage);
|
|
220
|
+
}
|
|
221
|
+
const data = await response.json();
|
|
222
|
+
let responseText = "I'm sorry, I didn't understand that. Could you please rephrase?";
|
|
223
|
+
let richContent = null;
|
|
224
|
+
let handoff = false;
|
|
225
|
+
if (data.queryResult?.parameters?.fields?.handoff?.boolValue === true) {
|
|
226
|
+
handoff = true;
|
|
227
|
+
} else if (data.queryResult?.responseMessages) {
|
|
228
|
+
for (const msg of data.queryResult.responseMessages) {
|
|
229
|
+
if (msg.payload) {
|
|
230
|
+
if (typeof msg.payload === "object") {
|
|
231
|
+
if (msg.payload.handoff === true) {
|
|
232
|
+
handoff = true;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
if (msg.payload.fields?.handoff?.boolValue === true) {
|
|
236
|
+
handoff = true;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (data.handoff === true) {
|
|
244
|
+
handoff = true;
|
|
245
|
+
}
|
|
246
|
+
if (data.queryResult?.responseMessages) {
|
|
247
|
+
const textMessages = data.queryResult.responseMessages.filter((msg) => msg.text).map((msg) => msg.text.text.join(" "));
|
|
248
|
+
if (textMessages.length > 0) {
|
|
249
|
+
responseText = textMessages.join(" ");
|
|
250
|
+
}
|
|
251
|
+
richContent = extractRichContent(data.queryResult.responseMessages);
|
|
252
|
+
} else if (data.queryResult?.fulfillmentText) {
|
|
253
|
+
responseText = data.queryResult.fulfillmentText;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
response: responseText,
|
|
257
|
+
session_id: sessionId,
|
|
258
|
+
source: "dialogflow",
|
|
259
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
260
|
+
...richContent && { richContent },
|
|
261
|
+
...handoff && { handoff: true }
|
|
262
|
+
};
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error("Error sending message to Dialogflow:", error);
|
|
265
|
+
const errorMessage = error.message || "Failed to send message";
|
|
266
|
+
if (errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
|
|
267
|
+
throw new Error("Authentication failed. Please check your service account key or access token.");
|
|
268
|
+
} else if (errorMessage.includes("403") || errorMessage.includes("Forbidden")) {
|
|
269
|
+
throw new Error("Access forbidden. Please check your Dialogflow API permissions.");
|
|
270
|
+
} else if (errorMessage.includes("404") || errorMessage.includes("Not Found")) {
|
|
271
|
+
throw new Error("Dialogflow agent not found. Please check your project ID, location, and agent ID.");
|
|
272
|
+
} else if (errorMessage.includes("CORS")) {
|
|
273
|
+
throw new Error("CORS error. Dialogflow API may not allow browser requests. Consider using a backend proxy.");
|
|
274
|
+
}
|
|
275
|
+
throw new Error(errorMessage);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
export {
|
|
279
|
+
createDialogflowSession,
|
|
280
|
+
sendDialogflowMessage
|
|
281
|
+
};
|
|
282
|
+
//# sourceMappingURL=dialogflowClient.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogflowClient.esm.js","sources":["../../src/services/dialogflowClient.ts"],"sourcesContent":["// services/dialogflowClient.ts\nimport { SignJWT, importPKCS8 } from 'jose';\n\nexport interface DialogflowConfig {\n dfProjectId: string;\n dfLocation: string;\n dfAgentId: string;\n serviceAccountKey?: any; // Service account JSON object\n accessToken?: string; // Alternative: provide access token directly\n languageCode?: string;\n}\n\nexport interface SessionResponse {\n session_id: string;\n message: string;\n richContent?: any;\n}\n\nexport interface ChatResponse {\n response: string;\n session_id: string;\n source: string;\n timestamp: string;\n richContent?: any;\n handoff?: boolean;\n}\n\n// Helper to get access token from service account using Web Crypto API\nasync function getAccessTokenFromServiceAccount(serviceAccountKey: any): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n \n // Format the private key - ensure it's properly formatted for PKCS#8\n let privateKeyPem = serviceAccountKey.private_key;\n \n // Google service account keys should already be in PKCS#8 format\n // But we need to ensure proper formatting with newlines\n if (privateKeyPem) {\n // Remove any existing whitespace/newlines\n privateKeyPem = privateKeyPem.trim();\n \n // If it doesn't have headers, it's just the base64 content\n if (!privateKeyPem.includes('-----BEGIN')) {\n // Wrap the base64 content with proper headers\n // Split into 64-character lines for proper PEM format\n const keyContent = privateKeyPem.replace(/\\s/g, '');\n const formattedKey = keyContent.match(/.{1,64}/g)?.join('\\n') || keyContent;\n privateKeyPem = `-----BEGIN PRIVATE KEY-----\\n${formattedKey}\\n-----END PRIVATE KEY-----`;\n } else {\n // Key has headers, but ensure proper line breaks\n // Normalize line breaks to \\n\n privateKeyPem = privateKeyPem.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n \n // If it's RSA PRIVATE KEY (PKCS#1), we need to note that jose can't convert it\n // Google service accounts should provide PKCS#8, but if not, we'll try to use as-is\n if (privateKeyPem.includes('BEGIN RSA PRIVATE KEY')) {\n throw new Error(\n 'Private key is in PKCS#1 format (RSA PRIVATE KEY). ' +\n 'Please download a new service account key from Google Cloud Console. ' +\n 'The key should be in PKCS#8 format (PRIVATE KEY).'\n );\n }\n \n // Ensure the key content is properly formatted (64 chars per line)\n const keyMatch = privateKeyPem.match(/-----BEGIN PRIVATE KEY-----\\n?([\\s\\S]*?)\\n?-----END PRIVATE KEY-----/);\n if (keyMatch) {\n const keyContent = keyMatch[1].replace(/\\s/g, '');\n // Check if already properly formatted (has newlines every 64 chars)\n if (!keyContent.includes('\\n') || keyContent.length > 64) {\n const formattedKey = keyContent.match(/.{1,64}/g)?.join('\\n') || keyContent;\n privateKeyPem = `-----BEGIN PRIVATE KEY-----\\n${formattedKey}\\n-----END PRIVATE KEY-----`;\n }\n }\n }\n } else {\n throw new Error('Private key is missing from service account key');\n }\n \n try {\n // Import the private key (jose expects PKCS#8 format)\n const privateKey = await importPKCS8(privateKeyPem, 'RS256');\n \n // Create JWT\n const jwt = await new SignJWT({\n scope: 'https://www.googleapis.com/auth/cloud-platform',\n })\n .setProtectedHeader({ alg: 'RS256' })\n .setIssuedAt(now)\n .setExpirationTime(now + 3600)\n .setIssuer(serviceAccountKey.client_email)\n .setSubject(serviceAccountKey.client_email)\n .setAudience('https://oauth2.googleapis.com/token')\n .sign(privateKey);\n\n // Exchange JWT for access token\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json();\n throw new Error(error.error_description || 'Failed to get access token');\n }\n\n const data = await response.json();\n return data.access_token;\n } catch (error: any) {\n if (error.message && error.message.includes('pkcs8')) {\n throw new Error(\n 'Invalid private key format. The service account key must be in PKCS#8 format. ' +\n 'Please ensure your service account key JSON file has a properly formatted private_key field. ' +\n 'If you downloaded the key from Google Cloud Console, it should already be in the correct format.'\n );\n }\n throw error;\n }\n}\n\n// Get access token (either from service account or use provided token)\nasync function getAccessToken(config: DialogflowConfig): Promise<string> {\n if (config.accessToken) {\n return config.accessToken;\n }\n \n if (!config.serviceAccountKey) {\n throw new Error('Either serviceAccountKey or accessToken must be provided');\n }\n\n return await getAccessTokenFromServiceAccount(config.serviceAccountKey);\n}\n\n// Create session path\nfunction createSessionPath(projectId: string, location: string, agentId: string, sessionId: string): string {\n return `projects/${projectId}/locations/${location}/agents/${agentId}/sessions/${sessionId}`;\n}\n\n// Extract rich content from Dialogflow response\nfunction extractRichContent(responseMessages: any[]): any {\n let richContent = null;\n \n for (const msg of responseMessages) {\n if (msg.payload) {\n if (msg.payload.richContent) {\n richContent = msg.payload.richContent;\n break;\n }\n if (msg.payload.fields && msg.payload.fields.richContent) {\n const richContentValue = msg.payload.fields.richContent;\n if (richContentValue.listValue && richContentValue.listValue.values) {\n richContent = richContentValue.listValue.values.map((v: any) => {\n if (v.listValue && v.listValue.values) {\n return v.listValue.values.map((item: any) => {\n if (item.structValue && item.structValue.fields) {\n const fields = item.structValue.fields;\n if (fields.type && fields.options) {\n return {\n type: fields.type.stringValue || fields.type,\n options: fields.options.listValue\n ? fields.options.listValue.values.map((opt: any) => ({\n text: opt.structValue?.fields?.text?.stringValue || '',\n payload: opt.structValue?.fields?.payload?.stringValue || '',\n }))\n : [],\n };\n }\n }\n return item;\n });\n }\n return v;\n });\n } else if (typeof richContentValue === 'object' && !richContentValue.listValue) {\n richContent = richContentValue;\n }\n break;\n }\n }\n }\n \n return richContent;\n}\n\n/**\n * Create a new Dialogflow session\n * @param config - Dialogflow configuration\n * @returns Promise with session ID and welcome message\n */\nexport async function createDialogflowSession(config: DialogflowConfig): Promise<SessionResponse> {\n try {\n const accessToken = await getAccessToken(config);\n const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const location = config.dfLocation.split(' ')[0].trim(); // Extract just the location code\n const sessionPath = createSessionPath(\n config.dfProjectId,\n location,\n config.dfAgentId,\n sessionId\n );\n\n const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;\n\n // Get welcome message\n const request = {\n queryInput: {\n text: {\n text: 'hello',\n },\n languageCode: config.languageCode || 'en',\n },\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n \n let welcomeMessage = \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\";\n let richContent = null;\n\n if (data.queryResult?.responseMessages) {\n const textMessages = data.queryResult.responseMessages\n .filter((msg: any) => msg.text)\n .map((msg: any) => msg.text.text.join(' '));\n \n if (textMessages.length > 0) {\n welcomeMessage = textMessages.join(' ');\n }\n\n richContent = extractRichContent(data.queryResult.responseMessages);\n } else if (data.queryResult?.fulfillmentText) {\n welcomeMessage = data.queryResult.fulfillmentText;\n }\n\n return {\n session_id: sessionId,\n message: welcomeMessage,\n ...(richContent && { richContent }),\n };\n } catch (error: any) {\n console.error('Error creating Dialogflow session:', error);\n const errorMessage = error.message || 'Failed to create session';\n if (errorMessage.includes('401') || errorMessage.includes('Unauthorized')) {\n throw new Error('Authentication failed. Please check your service account key or access token.');\n } else if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {\n throw new Error('Access forbidden. Please check your Dialogflow API permissions.');\n } else if (errorMessage.includes('404') || errorMessage.includes('Not Found')) {\n throw new Error('Dialogflow agent not found. Please check your project ID, location, and agent ID.');\n }\n throw new Error(errorMessage);\n }\n}\n\n/**\n * Send a message to Dialogflow\n * @param message - The user's message\n * @param sessionId - The session ID\n * @param config - Dialogflow configuration\n * @returns Promise with bot response\n */\nexport async function sendDialogflowMessage(\n message: string,\n sessionId: string,\n config: DialogflowConfig\n): Promise<ChatResponse> {\n try {\n const accessToken = await getAccessToken(config);\n const location = config.dfLocation.split(' ')[0].trim(); // Extract just the location code\n const sessionPath = createSessionPath(\n config.dfProjectId,\n location,\n config.dfAgentId,\n sessionId\n );\n\n const apiEndpoint = `https://${location}-dialogflow.googleapis.com/v3/${sessionPath}:detectIntent`;\n\n const request = {\n queryInput: {\n text: {\n text: message.trim(),\n },\n languageCode: config.languageCode || 'en',\n },\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorData: any = {};\n try {\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { message: errorText || `HTTP ${response.status}` };\n }\n const errorMessage = errorData.error?.message || errorData.message || `HTTP error! status: ${response.status}`;\n console.error('Dialogflow API Error (sendMessage):', {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n endpoint: apiEndpoint,\n });\n throw new Error(errorMessage);\n }\n\n const data = await response.json();\n\n let responseText = \"I'm sorry, I didn't understand that. Could you please rephrase?\";\n let richContent = null;\n let handoff = false;\n\n // Check for handoff trigger\n if (data.queryResult?.parameters?.fields?.handoff?.boolValue === true) {\n handoff = true;\n } else if (data.queryResult?.responseMessages) {\n // Check in responseMessages payload\n for (const msg of data.queryResult.responseMessages) {\n if (msg.payload) {\n if (typeof msg.payload === 'object') {\n if (msg.payload.handoff === true) {\n handoff = true;\n break;\n }\n if (msg.payload.fields?.handoff?.boolValue === true) {\n handoff = true;\n break;\n }\n }\n }\n }\n }\n \n // Check at root level\n if (data.handoff === true) {\n handoff = true;\n }\n\n if (data.queryResult?.responseMessages) {\n const textMessages = data.queryResult.responseMessages\n .filter((msg: any) => msg.text)\n .map((msg: any) => msg.text.text.join(' '));\n \n if (textMessages.length > 0) {\n responseText = textMessages.join(' ');\n }\n\n richContent = extractRichContent(data.queryResult.responseMessages);\n } else if (data.queryResult?.fulfillmentText) {\n responseText = data.queryResult.fulfillmentText;\n }\n\n return {\n response: responseText,\n session_id: sessionId,\n source: 'dialogflow',\n timestamp: new Date().toISOString(),\n ...(richContent && { richContent }),\n ...(handoff && { handoff: true }),\n };\n } catch (error: any) {\n console.error('Error sending message to Dialogflow:', error);\n const errorMessage = error.message || 'Failed to send message';\n if (errorMessage.includes('401') || errorMessage.includes('Unauthorized')) {\n throw new Error('Authentication failed. Please check your service account key or access token.');\n } else if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {\n throw new Error('Access forbidden. Please check your Dialogflow API permissions.');\n } else if (errorMessage.includes('404') || errorMessage.includes('Not Found')) {\n throw new Error('Dialogflow agent not found. Please check your project ID, location, and agent ID.');\n } else if (errorMessage.includes('CORS')) {\n throw new Error('CORS error. Dialogflow API may not allow browser requests. Consider using a backend proxy.');\n }\n throw new Error(errorMessage);\n }\n}\n\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="chat_session_id";class s{constructor(){this.sessionId=null,this.sessionId=this.loadSessionId()}loadSessionId(){return"undefined"!=typeof localStorage?localStorage.getItem(e):null}saveSessionId(s){this.sessionId=s,"undefined"!=typeof localStorage&&(s?localStorage.setItem(e,s):localStorage.removeItem(e))}updateSessionFromResponse(e){const s=e?.data?.session_id||e?.session_id;s&&"string"==typeof s&&this.saveSessionId(s)}getSessionId(){return this.sessionId||""}getSessionHeader(){return{"X-Session-ID":this.getSessionId()}}}let o=null;exports.getSessionManager=function(){return o||(o=new s),o};
|
|
2
|
+
//# sourceMappingURL=sessionManager.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionManager.cjs.js","sources":["../../src/services/sessionManager.ts"],"sourcesContent":["// services/sessionManager.ts\n\nconst SESSION_KEY = 'chat_session_id';\n\nclass ChatSessionManager {\n private sessionId: string | null = null;\n\n constructor() {\n this.sessionId = this.loadSessionId();\n }\n\n loadSessionId(): string | null {\n if (typeof localStorage !== 'undefined') {\n return localStorage.getItem(SESSION_KEY);\n }\n return null;\n }\n\n saveSessionId(sessionId: string | null): void {\n this.sessionId = sessionId;\n if (typeof localStorage !== 'undefined') {\n if (sessionId) {\n localStorage.setItem(SESSION_KEY, sessionId);\n } else {\n localStorage.removeItem(SESSION_KEY);\n }\n }\n }\n\n updateSessionFromResponse(responseData: any): void {\n const sid = responseData?.data?.session_id || responseData?.session_id;\n if (sid && typeof sid === 'string') {\n this.saveSessionId(sid);\n }\n }\n\n getSessionId(): string {\n return this.sessionId || '';\n }\n\n getSessionHeader(): Record<string, string> {\n return {\n 'X-Session-ID': this.getSessionId()\n };\n }\n}\n\n// Export singleton instance\nlet sessionManagerInstance: ChatSessionManager | null = null;\n\nexport function getSessionManager(): ChatSessionManager {\n if (!sessionManagerInstance) {\n sessionManagerInstance = new ChatSessionManager();\n }\n return sessionManagerInstance;\n}\n\nexport function createSessionManager(): ChatSessionManager {\n return new ChatSessionManager();\n}\n\nexport default ChatSessionManager;\n"],"names":["SESSION_KEY","ChatSessionManager","constructor","this","sessionId","loadSessionId","localStorage","getItem","saveSessionId","setItem","removeItem","updateSessionFromResponse","responseData","sid","data","session_id","getSessionId","getSessionHeader","sessionManagerInstance"],"mappings":"gFAEA,MAAMA,EAAc,kBAEpB,MAAMC,EAGJ,WAAAC,GAFAC,KAAQC,UAA2B,KAGjCD,KAAKC,UAAYD,KAAKE,eACxB,CAEA,aAAAA,GACE,MAA4B,oBAAjBC,aACFA,aAAaC,QAAQP,GAEvB,IACT,CAEA,aAAAQ,CAAcJ,GACZD,KAAKC,UAAYA,EACW,oBAAjBE,eACLF,EACFE,aAAaG,QAAQT,EAAaI,GAElCE,aAAaI,WAAWV,GAG9B,CAEA,yBAAAW,CAA0BC,GACxB,MAAMC,EAAMD,GAAcE,MAAMC,YAAcH,GAAcG,WACxDF,GAAsB,iBAARA,GAChBV,KAAKK,cAAcK,EAEvB,CAEA,YAAAG,GACE,OAAOb,KAAKC,WAAa,EAC3B,CAEA,gBAAAa,GACE,MAAO,CACL,eAAgBd,KAAKa,eAEzB,EAIF,IAAIE,EAAoD,+BAEjD,WAIL,OAHKA,IACHA,EAAyB,IAAIjB,GAExBiB,CACT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare class ChatSessionManager {
|
|
2
|
+
private sessionId;
|
|
3
|
+
constructor();
|
|
4
|
+
loadSessionId(): string | null;
|
|
5
|
+
saveSessionId(sessionId: string | null): void;
|
|
6
|
+
updateSessionFromResponse(responseData: any): void;
|
|
7
|
+
getSessionId(): string;
|
|
8
|
+
getSessionHeader(): Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getSessionManager(): ChatSessionManager;
|
|
11
|
+
export declare function createSessionManager(): ChatSessionManager;
|
|
12
|
+
export default ChatSessionManager;
|
|
13
|
+
//# sourceMappingURL=sessionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionManager.d.ts","sourceRoot":"","sources":["../../src/services/sessionManager.ts"],"names":[],"mappings":"AAIA,cAAM,kBAAkB;IACtB,OAAO,CAAC,SAAS,CAAuB;;IAMxC,aAAa,IAAI,MAAM,GAAG,IAAI;IAO9B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAW7C,yBAAyB,CAAC,YAAY,EAAE,GAAG,GAAG,IAAI;IAOlD,YAAY,IAAI,MAAM;IAItB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAK3C;AAKD,wBAAgB,iBAAiB,IAAI,kBAAkB,CAKtD;AAED,wBAAgB,oBAAoB,IAAI,kBAAkB,CAEzD;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const SESSION_KEY = "chat_session_id";
|
|
2
|
+
class ChatSessionManager {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.sessionId = null;
|
|
5
|
+
this.sessionId = this.loadSessionId();
|
|
6
|
+
}
|
|
7
|
+
loadSessionId() {
|
|
8
|
+
if (typeof localStorage !== "undefined") {
|
|
9
|
+
return localStorage.getItem(SESSION_KEY);
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
saveSessionId(sessionId) {
|
|
14
|
+
this.sessionId = sessionId;
|
|
15
|
+
if (typeof localStorage !== "undefined") {
|
|
16
|
+
if (sessionId) {
|
|
17
|
+
localStorage.setItem(SESSION_KEY, sessionId);
|
|
18
|
+
} else {
|
|
19
|
+
localStorage.removeItem(SESSION_KEY);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
updateSessionFromResponse(responseData) {
|
|
24
|
+
const sid = responseData?.data?.session_id || responseData?.session_id;
|
|
25
|
+
if (sid && typeof sid === "string") {
|
|
26
|
+
this.saveSessionId(sid);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
getSessionId() {
|
|
30
|
+
return this.sessionId || "";
|
|
31
|
+
}
|
|
32
|
+
getSessionHeader() {
|
|
33
|
+
return {
|
|
34
|
+
"X-Session-ID": this.getSessionId()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
let sessionManagerInstance = null;
|
|
39
|
+
function getSessionManager() {
|
|
40
|
+
if (!sessionManagerInstance) {
|
|
41
|
+
sessionManagerInstance = new ChatSessionManager();
|
|
42
|
+
}
|
|
43
|
+
return sessionManagerInstance;
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
getSessionManager
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=sessionManager.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionManager.esm.js","sources":["../../src/services/sessionManager.ts"],"sourcesContent":["// services/sessionManager.ts\n\nconst SESSION_KEY = 'chat_session_id';\n\nclass ChatSessionManager {\n private sessionId: string | null = null;\n\n constructor() {\n this.sessionId = this.loadSessionId();\n }\n\n loadSessionId(): string | null {\n if (typeof localStorage !== 'undefined') {\n return localStorage.getItem(SESSION_KEY);\n }\n return null;\n }\n\n saveSessionId(sessionId: string | null): void {\n this.sessionId = sessionId;\n if (typeof localStorage !== 'undefined') {\n if (sessionId) {\n localStorage.setItem(SESSION_KEY, sessionId);\n } else {\n localStorage.removeItem(SESSION_KEY);\n }\n }\n }\n\n updateSessionFromResponse(responseData: any): void {\n const sid = responseData?.data?.session_id || responseData?.session_id;\n if (sid && typeof sid === 'string') {\n this.saveSessionId(sid);\n }\n }\n\n getSessionId(): string {\n return this.sessionId || '';\n }\n\n getSessionHeader(): Record<string, string> {\n return {\n 'X-Session-ID': this.getSessionId()\n };\n }\n}\n\n// Export singleton instance\nlet sessionManagerInstance: ChatSessionManager | null = null;\n\nexport function getSessionManager(): ChatSessionManager {\n if (!sessionManagerInstance) {\n sessionManagerInstance = new ChatSessionManager();\n }\n return sessionManagerInstance;\n}\n\nexport function createSessionManager(): ChatSessionManager {\n return new ChatSessionManager();\n}\n\nexport default ChatSessionManager;\n"],"names":[],"mappings":"AAEA,MAAM,cAAc;AAEpB,MAAM,mBAAmB;AAAA,EAGvB,cAAc;AAFd,SAAQ,YAA2B;AAGjC,SAAK,YAAY,KAAK,cAAA;AAAA,EACxB;AAAA,EAEA,gBAA+B;AAC7B,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO,aAAa,QAAQ,WAAW;AAAA,IACzC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAAgC;AAC5C,SAAK,YAAY;AACjB,QAAI,OAAO,iBAAiB,aAAa;AACvC,UAAI,WAAW;AACb,qBAAa,QAAQ,aAAa,SAAS;AAAA,MAC7C,OAAO;AACL,qBAAa,WAAW,WAAW;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,0BAA0B,cAAyB;AACjD,UAAM,MAAM,cAAc,MAAM,cAAc,cAAc;AAC5D,QAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,WAAK,cAAc,GAAG;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,eAAuB;AACrB,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA,EAEA,mBAA2C;AACzC,WAAO;AAAA,MACL,gBAAgB,KAAK,aAAA;AAAA,IAAa;AAAA,EAEtC;AACF;AAGA,IAAI,yBAAoD;AAEjD,SAAS,oBAAwC;AACtD,MAAI,CAAC,wBAAwB;AAC3B,6BAAyB,IAAI,mBAAA;AAAA,EAC/B;AACA,SAAO;AACT;"}
|
package/dist/styles.css
ADDED
|
File without changes
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { DialogflowConfig, SessionResponse, ChatResponse, } from './services/dialogflowClient';
|
|
2
|
+
export type { SupportChatSession, SupportMessage, ChatInfo, WebSocketMessage, ChatServiceConfig, } from './services/chatService';
|
|
3
|
+
export type { ChatWidgetProps } from './components/ChatWidget';
|
|
4
|
+
export type { ChatMode, UseChatModeReturn } from './hooks/useChatMode';
|
|
5
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,6BAA6B,CAAC;AAErC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG/D,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|