open-chat-studio-widget 0.9.0 → 0.9.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/dist/cjs/{index-DDod9Zyw.js → index-fFSp-Z_h.js} +3 -3
- package/dist/cjs/{index-DDod9Zyw.js.map → index-fFSp-Z_h.js.map} +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js +11 -9
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.js +1 -1
- package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
- package/dist/collection/components/ocs-chat/ocs-chat.js +1 -1
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/collection/services/chat-session-service.js +7 -2
- package/dist/collection/services/chat-session-service.js.map +1 -1
- package/dist/collection/services/file-attachment-manager.js +2 -5
- package/dist/collection/services/file-attachment-manager.js.map +1 -1
- package/dist/components/open-chat-studio-widget.js +10 -8
- package/dist/components/open-chat-studio-widget.js.map +1 -1
- package/dist/esm/{index-iUBQH9om.js → index-ythTKHg-.js} +3 -3
- package/dist/esm/{index-iUBQH9om.js.map → index-ythTKHg-.js.map} +1 -1
- package/dist/esm/loader.js +2 -2
- package/dist/esm/open-chat-studio-widget.entry.js +11 -9
- package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.js +2 -2
- package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
- package/dist/open-chat-studio-widget/{p-9c925476.entry.js → p-2d31a15c.entry.js} +4 -4
- package/dist/open-chat-studio-widget/p-2d31a15c.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/{p-iUBQH9om.js → p-ythTKHg-.js} +2 -2
- package/dist/open-chat-studio-widget/{p-iUBQH9om.js.map → p-ythTKHg-.js.map} +1 -1
- package/dist/types/services/chat-session-service.d.ts +2 -0
- package/dist/types/services/file-attachment-manager.d.ts +2 -1
- package/package.json +1 -1
- package/dist/open-chat-studio-widget/p-9c925476.entry.js.map +0 -1
|
@@ -235,15 +235,20 @@ export class ChatSessionService {
|
|
|
235
235
|
}
|
|
236
236
|
throw new Error(message);
|
|
237
237
|
}
|
|
238
|
-
|
|
238
|
+
/** Headers for multipart requests (no Content-Type — fetch sets the boundary). */
|
|
239
|
+
getUploadHeaders() {
|
|
239
240
|
const headers = this.getCommonHeaders();
|
|
240
|
-
headers['Content-Type'] = 'application/json';
|
|
241
241
|
const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
|
|
242
242
|
if (csrfToken) {
|
|
243
243
|
headers['X-CSRFToken'] = csrfToken;
|
|
244
244
|
}
|
|
245
245
|
return headers;
|
|
246
246
|
}
|
|
247
|
+
getJsonHeaders() {
|
|
248
|
+
const headers = this.getUploadHeaders();
|
|
249
|
+
headers['Content-Type'] = 'application/json';
|
|
250
|
+
return headers;
|
|
251
|
+
}
|
|
247
252
|
getCommonHeaders() {
|
|
248
253
|
const headers = {
|
|
249
254
|
'x-ocs-widget-version': this.widgetVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-session-service.js","sourceRoot":"","sources":["../../src/services/chat-session-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getCSRFToken } from '../utils/cookies';\n\nexport class SessionAccessError extends Error {\n readonly status: number;\n readonly code?: string;\n\n constructor(status: number, code: string | undefined, message: string) {\n super(message);\n this.name = 'SessionAccessError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport type ChatRole = 'system' | 'user' | 'assistant';\n\nexport interface ChatAttachment {\n name: string;\n content_type: string;\n size: number;\n}\n\nexport interface ChatMessage {\n created_at: string;\n role: ChatRole;\n content: string;\n metadata?: unknown;\n attachments?: ChatAttachment[];\n}\n\nexport interface ChatStartSessionResponse {\n session_id: string;\n session_token?: string | null;\n chatbot: unknown;\n participant: unknown;\n}\n\nexport interface ChatSendMessageResponse {\n task_id: string;\n status: 'processing' | 'completed' | 'error';\n error?: string;\n}\n\nexport interface ChatTaskPollResponse {\n message?: ChatMessage;\n status: 'processing' | 'complete';\n error?: string;\n}\n\nexport interface ChatPollResponse {\n messages: ChatMessage[];\n has_more: boolean;\n session_status: 'active' | 'ended';\n}\n\nexport interface ChatSessionServiceOptions {\n apiBaseUrl: string;\n embedKey?: string;\n widgetVersion: string;\n sessionToken?: string;\n csrfTokenProvider?: (apiBaseUrl: string) => string | undefined;\n taskPollingIntervalMs?: number;\n taskPollingMaxAttempts?: number;\n messagePollingIntervalMs?: number;\n}\n\nexport interface TaskPollingCallbacks {\n onMessage: (message: ChatMessage) => void;\n onProgress?: (message: string) => void;\n onTimeout?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport interface TaskPollingHandle {\n cancel: () => void;\n}\n\nexport interface MessagePollingCallbacks {\n getSince: () => string | undefined;\n onMessages: (messages: ChatMessage[]) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface MessagePollingHandle {\n stop: () => void;\n}\n\nexport class ChatSessionService {\n private readonly apiBaseUrl: string;\n private readonly embedKey?: string;\n private readonly widgetVersion: string;\n private sessionToken?: string;\n private readonly csrfTokenProvider: (apiBaseUrl: string) => string | undefined;\n private readonly taskPollingIntervalMs: number;\n private readonly taskPollingMaxAttempts: number;\n private readonly messagePollingIntervalMs: number;\n private messagePollingTimer?: ReturnType<typeof setInterval>;\n private loggedSunsetLevel?: 'warn' | 'error';\n private static readonly MAX_HISTORY_PAGES = 40;\n\n constructor(options: ChatSessionServiceOptions) {\n this.apiBaseUrl = options.apiBaseUrl;\n this.embedKey = options.embedKey;\n this.widgetVersion = options.widgetVersion;\n this.sessionToken = options.sessionToken;\n this.csrfTokenProvider = options.csrfTokenProvider ?? getCSRFToken;\n this.taskPollingIntervalMs = options.taskPollingIntervalMs ?? 1000;\n this.taskPollingMaxAttempts = options.taskPollingMaxAttempts ?? 120;\n this.messagePollingIntervalMs = options.messagePollingIntervalMs ?? 30000;\n }\n\n async startSession(requestBody: Record<string, unknown>): Promise<ChatStartSessionResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/start/`, {\n method: 'POST',\n headers: this.getJsonHeaders(),\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to start session');\n }\n\n return response.json() as Promise<ChatStartSessionResponse>;\n }\n\n async sendMessage(sessionId: string, payload: Record<string, unknown>): Promise<ChatSendMessageResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {\n method: 'POST',\n headers: this.getJsonHeaders(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to send message');\n }\n\n return response.json() as Promise<ChatSendMessageResponse>;\n }\n\n async pollTaskOnce(sessionId: string, taskId: string): Promise<ChatTaskPollResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`, {\n headers: this.getCommonHeaders(),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to poll task');\n }\n\n return response.json() as Promise<ChatTaskPollResponse>;\n }\n\n pollTask(sessionId: string, taskId: string, callbacks: TaskPollingCallbacks): TaskPollingHandle {\n let attempts = 0;\n let cancelled = false;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const scheduleNextPoll = () => {\n timeoutId = setTimeout(() => {\n void poll();\n }, this.taskPollingIntervalMs);\n };\n\n const poll = async () => {\n if (cancelled) {\n return;\n }\n\n try {\n const data = await this.pollTaskOnce(sessionId, taskId);\n\n if (data.error) {\n throw new Error(data.error);\n }\n\n if (data.status === 'complete' && data.message) {\n callbacks.onMessage(data.message);\n return;\n }\n\n if (data.status === 'processing' && data.message?.content && callbacks.onProgress) {\n callbacks.onProgress(data.message.content);\n }\n\n attempts += 1;\n if (attempts >= this.taskPollingMaxAttempts) {\n if (callbacks.onTimeout) {\n callbacks.onTimeout();\n }\n return;\n }\n\n scheduleNextPoll();\n } catch (error) {\n if (callbacks.onError) {\n callbacks.onError(error instanceof Error ? error : new Error('Failed to get response'));\n }\n }\n };\n\n void poll();\n\n return {\n cancel: () => {\n cancelled = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n },\n };\n }\n\n async fetchMessages(sessionId: string, since?: string): Promise<ChatPollResponse> {\n const url = new URL(`${this.apiBaseUrl}/api/chat/${sessionId}/poll/`);\n if (since) {\n url.searchParams.set('since', since);\n }\n\n const response = await this.request(url.toString(), {\n headers: this.getCommonHeaders(),\n });\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to poll messages');\n }\n\n return response.json() as Promise<ChatPollResponse>;\n }\n\n /**\n * Fetch the complete message history for a session by paging through the\n * poll endpoint until no more messages remain.\n */\n async fetchAllMessages(sessionId: string): Promise<ChatMessage[]> {\n const allMessages: ChatMessage[] = [];\n let since: string | undefined;\n let hasMore = true;\n\n for (let page = 0; hasMore && page < ChatSessionService.MAX_HISTORY_PAGES; page++) {\n const data = await this.fetchMessages(sessionId, since);\n allMessages.push(...data.messages);\n hasMore = data.has_more && data.messages.length > 0;\n // The server returns pages in ascending created_at order and `since` is\n // exclusive (created_at > since), so the last message's timestamp is the\n // next page cursor.\n since = data.messages.at(-1)?.created_at;\n }\n\n if (hasMore) {\n console.warn('Chat history truncated after', ChatSessionService.MAX_HISTORY_PAGES, 'pages');\n }\n\n return allMessages;\n }\n\n startMessagePolling(sessionId: string, callbacks: MessagePollingCallbacks): MessagePollingHandle {\n const poll = async () => {\n try {\n const since = callbacks.getSince();\n const data = await this.fetchMessages(sessionId, since);\n if (data.messages.length > 0) {\n callbacks.onMessages(data.messages);\n }\n } catch (error) {\n if (callbacks.onError) {\n callbacks.onError(error instanceof Error ? error : new Error('Failed to poll messages'));\n }\n }\n };\n\n // perform an initial poll immediately\n void poll();\n\n this.messagePollingTimer = setInterval(() => {\n void poll();\n }, this.messagePollingIntervalMs);\n\n return {\n stop: () => this.stopMessagePolling(),\n };\n }\n\n stopMessagePolling(): void {\n if (this.messagePollingTimer) {\n clearInterval(this.messagePollingTimer);\n this.messagePollingTimer = undefined;\n }\n }\n\n setSessionToken(token?: string): void {\n this.sessionToken = token;\n }\n\n private async request(input: string, init?: RequestInit): Promise<Response> {\n const response = await fetch(input, init);\n this.checkSunsetHeaders(response);\n return response;\n }\n\n /**\n * Log a deprecation warning (RFC 8594 `Deprecation`/`Sunset`/`Link` headers)\n * when the server reports that this widget version is deprecated. Warns\n * during the deprecation window and errors once the sunset date has passed.\n * Logs at most once per level so polling does not flood the console.\n */\n private checkSunsetHeaders(response: Response): void {\n const headers = response?.headers;\n if (!headers || typeof headers.get !== 'function') {\n return;\n }\n if (headers.get('Deprecation') !== 'true') {\n return;\n }\n\n const sunsetAt = this.parseSunsetDate(headers.get('Sunset'));\n const pastSunset = sunsetAt !== null && Date.now() >= sunsetAt.getTime();\n const level: 'warn' | 'error' = pastSunset ? 'error' : 'warn';\n if (this.loggedSunsetLevel === level) {\n return;\n }\n this.loggedSunsetLevel = level;\n\n const upgradeUrl = this.parseSuccessorUrl(headers.get('Link'));\n const upgradeSuffix = upgradeUrl ? ` Upgrade: ${upgradeUrl}` : '';\n const sunsetText = sunsetAt ? sunsetAt.toUTCString() : 'an upcoming date';\n if (level === 'error') {\n console.error(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is past its sunset date ` + `(${sunsetText}) and may stop working.${upgradeSuffix}`);\n } else {\n console.warn(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is deprecated and will stop ` + `working after ${sunsetText}.${upgradeSuffix}`);\n }\n }\n\n private parseSunsetDate(sunset: string | null): Date | null {\n if (!sunset) {\n return null;\n }\n const parsed = new Date(sunset);\n return Number.isNaN(parsed.getTime()) ? null : parsed;\n }\n\n private parseSuccessorUrl(link: string | null): string | undefined {\n const match = link?.match(/<([^>]+)>\\s*;\\s*rel=\"?successor-version\"?/);\n return match?.[1];\n }\n\n private async raiseForStatus(response: Response, fallbackPrefix: string): Promise<never> {\n let message = `${fallbackPrefix}: ${response.statusText}`;\n let code: string | undefined;\n try {\n const data = (await response.json()) as { error?: string; code?: string };\n if (data?.error) {\n message = data.error;\n }\n code = data?.code;\n } catch {\n // non-JSON body; keep statusText fallback\n }\n if (response.status === 403) {\n throw new SessionAccessError(response.status, code, message);\n }\n throw new Error(message);\n }\n\n private getJsonHeaders(): Record<string, string> {\n const headers = this.getCommonHeaders();\n headers['Content-Type'] = 'application/json';\n\n const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);\n if (csrfToken) {\n headers['X-CSRFToken'] = csrfToken;\n }\n\n return headers;\n }\n\n private getCommonHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'x-ocs-widget-version': this.widgetVersion,\n };\n\n if (this.embedKey) {\n headers['X-Embed-Key'] = this.embedKey;\n }\n\n if (this.sessionToken) {\n headers['X-Session-Token'] = this.sessionToken;\n }\n\n return headers;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-session-service.js","sourceRoot":"","sources":["../../src/services/chat-session-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getCSRFToken } from '../utils/cookies';\n\nexport class SessionAccessError extends Error {\n readonly status: number;\n readonly code?: string;\n\n constructor(status: number, code: string | undefined, message: string) {\n super(message);\n this.name = 'SessionAccessError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport type ChatRole = 'system' | 'user' | 'assistant';\n\nexport interface ChatAttachment {\n name: string;\n content_type: string;\n size: number;\n}\n\nexport interface ChatMessage {\n created_at: string;\n role: ChatRole;\n content: string;\n metadata?: unknown;\n attachments?: ChatAttachment[];\n}\n\nexport interface ChatStartSessionResponse {\n session_id: string;\n session_token?: string | null;\n chatbot: unknown;\n participant: unknown;\n}\n\nexport interface ChatSendMessageResponse {\n task_id: string;\n status: 'processing' | 'completed' | 'error';\n error?: string;\n}\n\nexport interface ChatTaskPollResponse {\n message?: ChatMessage;\n status: 'processing' | 'complete';\n error?: string;\n}\n\nexport interface ChatPollResponse {\n messages: ChatMessage[];\n has_more: boolean;\n session_status: 'active' | 'ended';\n}\n\nexport interface ChatSessionServiceOptions {\n apiBaseUrl: string;\n embedKey?: string;\n widgetVersion: string;\n sessionToken?: string;\n csrfTokenProvider?: (apiBaseUrl: string) => string | undefined;\n taskPollingIntervalMs?: number;\n taskPollingMaxAttempts?: number;\n messagePollingIntervalMs?: number;\n}\n\nexport interface TaskPollingCallbacks {\n onMessage: (message: ChatMessage) => void;\n onProgress?: (message: string) => void;\n onTimeout?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport interface TaskPollingHandle {\n cancel: () => void;\n}\n\nexport interface MessagePollingCallbacks {\n getSince: () => string | undefined;\n onMessages: (messages: ChatMessage[]) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface MessagePollingHandle {\n stop: () => void;\n}\n\nexport class ChatSessionService {\n private readonly apiBaseUrl: string;\n private readonly embedKey?: string;\n private readonly widgetVersion: string;\n private sessionToken?: string;\n private readonly csrfTokenProvider: (apiBaseUrl: string) => string | undefined;\n private readonly taskPollingIntervalMs: number;\n private readonly taskPollingMaxAttempts: number;\n private readonly messagePollingIntervalMs: number;\n private messagePollingTimer?: ReturnType<typeof setInterval>;\n private loggedSunsetLevel?: 'warn' | 'error';\n private static readonly MAX_HISTORY_PAGES = 40;\n\n constructor(options: ChatSessionServiceOptions) {\n this.apiBaseUrl = options.apiBaseUrl;\n this.embedKey = options.embedKey;\n this.widgetVersion = options.widgetVersion;\n this.sessionToken = options.sessionToken;\n this.csrfTokenProvider = options.csrfTokenProvider ?? getCSRFToken;\n this.taskPollingIntervalMs = options.taskPollingIntervalMs ?? 1000;\n this.taskPollingMaxAttempts = options.taskPollingMaxAttempts ?? 120;\n this.messagePollingIntervalMs = options.messagePollingIntervalMs ?? 30000;\n }\n\n async startSession(requestBody: Record<string, unknown>): Promise<ChatStartSessionResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/start/`, {\n method: 'POST',\n headers: this.getJsonHeaders(),\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to start session');\n }\n\n return response.json() as Promise<ChatStartSessionResponse>;\n }\n\n async sendMessage(sessionId: string, payload: Record<string, unknown>): Promise<ChatSendMessageResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {\n method: 'POST',\n headers: this.getJsonHeaders(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to send message');\n }\n\n return response.json() as Promise<ChatSendMessageResponse>;\n }\n\n async pollTaskOnce(sessionId: string, taskId: string): Promise<ChatTaskPollResponse> {\n const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`, {\n headers: this.getCommonHeaders(),\n });\n\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to poll task');\n }\n\n return response.json() as Promise<ChatTaskPollResponse>;\n }\n\n pollTask(sessionId: string, taskId: string, callbacks: TaskPollingCallbacks): TaskPollingHandle {\n let attempts = 0;\n let cancelled = false;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const scheduleNextPoll = () => {\n timeoutId = setTimeout(() => {\n void poll();\n }, this.taskPollingIntervalMs);\n };\n\n const poll = async () => {\n if (cancelled) {\n return;\n }\n\n try {\n const data = await this.pollTaskOnce(sessionId, taskId);\n\n if (data.error) {\n throw new Error(data.error);\n }\n\n if (data.status === 'complete' && data.message) {\n callbacks.onMessage(data.message);\n return;\n }\n\n if (data.status === 'processing' && data.message?.content && callbacks.onProgress) {\n callbacks.onProgress(data.message.content);\n }\n\n attempts += 1;\n if (attempts >= this.taskPollingMaxAttempts) {\n if (callbacks.onTimeout) {\n callbacks.onTimeout();\n }\n return;\n }\n\n scheduleNextPoll();\n } catch (error) {\n if (callbacks.onError) {\n callbacks.onError(error instanceof Error ? error : new Error('Failed to get response'));\n }\n }\n };\n\n void poll();\n\n return {\n cancel: () => {\n cancelled = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n },\n };\n }\n\n async fetchMessages(sessionId: string, since?: string): Promise<ChatPollResponse> {\n const url = new URL(`${this.apiBaseUrl}/api/chat/${sessionId}/poll/`);\n if (since) {\n url.searchParams.set('since', since);\n }\n\n const response = await this.request(url.toString(), {\n headers: this.getCommonHeaders(),\n });\n if (!response.ok) {\n await this.raiseForStatus(response, 'Failed to poll messages');\n }\n\n return response.json() as Promise<ChatPollResponse>;\n }\n\n /**\n * Fetch the complete message history for a session by paging through the\n * poll endpoint until no more messages remain.\n */\n async fetchAllMessages(sessionId: string): Promise<ChatMessage[]> {\n const allMessages: ChatMessage[] = [];\n let since: string | undefined;\n let hasMore = true;\n\n for (let page = 0; hasMore && page < ChatSessionService.MAX_HISTORY_PAGES; page++) {\n const data = await this.fetchMessages(sessionId, since);\n allMessages.push(...data.messages);\n hasMore = data.has_more && data.messages.length > 0;\n // The server returns pages in ascending created_at order and `since` is\n // exclusive (created_at > since), so the last message's timestamp is the\n // next page cursor.\n since = data.messages.at(-1)?.created_at;\n }\n\n if (hasMore) {\n console.warn('Chat history truncated after', ChatSessionService.MAX_HISTORY_PAGES, 'pages');\n }\n\n return allMessages;\n }\n\n startMessagePolling(sessionId: string, callbacks: MessagePollingCallbacks): MessagePollingHandle {\n const poll = async () => {\n try {\n const since = callbacks.getSince();\n const data = await this.fetchMessages(sessionId, since);\n if (data.messages.length > 0) {\n callbacks.onMessages(data.messages);\n }\n } catch (error) {\n if (callbacks.onError) {\n callbacks.onError(error instanceof Error ? error : new Error('Failed to poll messages'));\n }\n }\n };\n\n // perform an initial poll immediately\n void poll();\n\n this.messagePollingTimer = setInterval(() => {\n void poll();\n }, this.messagePollingIntervalMs);\n\n return {\n stop: () => this.stopMessagePolling(),\n };\n }\n\n stopMessagePolling(): void {\n if (this.messagePollingTimer) {\n clearInterval(this.messagePollingTimer);\n this.messagePollingTimer = undefined;\n }\n }\n\n setSessionToken(token?: string): void {\n this.sessionToken = token;\n }\n\n private async request(input: string, init?: RequestInit): Promise<Response> {\n const response = await fetch(input, init);\n this.checkSunsetHeaders(response);\n return response;\n }\n\n /**\n * Log a deprecation warning (RFC 8594 `Deprecation`/`Sunset`/`Link` headers)\n * when the server reports that this widget version is deprecated. Warns\n * during the deprecation window and errors once the sunset date has passed.\n * Logs at most once per level so polling does not flood the console.\n */\n private checkSunsetHeaders(response: Response): void {\n const headers = response?.headers;\n if (!headers || typeof headers.get !== 'function') {\n return;\n }\n if (headers.get('Deprecation') !== 'true') {\n return;\n }\n\n const sunsetAt = this.parseSunsetDate(headers.get('Sunset'));\n const pastSunset = sunsetAt !== null && Date.now() >= sunsetAt.getTime();\n const level: 'warn' | 'error' = pastSunset ? 'error' : 'warn';\n if (this.loggedSunsetLevel === level) {\n return;\n }\n this.loggedSunsetLevel = level;\n\n const upgradeUrl = this.parseSuccessorUrl(headers.get('Link'));\n const upgradeSuffix = upgradeUrl ? ` Upgrade: ${upgradeUrl}` : '';\n const sunsetText = sunsetAt ? sunsetAt.toUTCString() : 'an upcoming date';\n if (level === 'error') {\n console.error(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is past its sunset date ` + `(${sunsetText}) and may stop working.${upgradeSuffix}`);\n } else {\n console.warn(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is deprecated and will stop ` + `working after ${sunsetText}.${upgradeSuffix}`);\n }\n }\n\n private parseSunsetDate(sunset: string | null): Date | null {\n if (!sunset) {\n return null;\n }\n const parsed = new Date(sunset);\n return Number.isNaN(parsed.getTime()) ? null : parsed;\n }\n\n private parseSuccessorUrl(link: string | null): string | undefined {\n const match = link?.match(/<([^>]+)>\\s*;\\s*rel=\"?successor-version\"?/);\n return match?.[1];\n }\n\n private async raiseForStatus(response: Response, fallbackPrefix: string): Promise<never> {\n let message = `${fallbackPrefix}: ${response.statusText}`;\n let code: string | undefined;\n try {\n const data = (await response.json()) as { error?: string; code?: string };\n if (data?.error) {\n message = data.error;\n }\n code = data?.code;\n } catch {\n // non-JSON body; keep statusText fallback\n }\n if (response.status === 403) {\n throw new SessionAccessError(response.status, code, message);\n }\n throw new Error(message);\n }\n\n /** Headers for multipart requests (no Content-Type — fetch sets the boundary). */\n getUploadHeaders(): Record<string, string> {\n const headers = this.getCommonHeaders();\n\n const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);\n if (csrfToken) {\n headers['X-CSRFToken'] = csrfToken;\n }\n\n return headers;\n }\n\n private getJsonHeaders(): Record<string, string> {\n const headers = this.getUploadHeaders();\n headers['Content-Type'] = 'application/json';\n return headers;\n }\n\n private getCommonHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'x-ocs-widget-version': this.widgetVersion,\n };\n\n if (this.embedKey) {\n headers['X-Embed-Key'] = this.embedKey;\n }\n\n if (this.sessionToken) {\n headers['X-Session-Token'] = this.sessionToken;\n }\n\n return headers;\n }\n}\n"]}
|
|
@@ -42,6 +42,7 @@ export class FileAttachmentManager {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
async uploadPendingFiles(existingFiles, context) {
|
|
45
|
+
var _a;
|
|
45
46
|
if (existingFiles.length === 0) {
|
|
46
47
|
return { selectedFiles: existingFiles, uploadedIds: [] };
|
|
47
48
|
}
|
|
@@ -59,13 +60,9 @@ export class FileAttachmentManager {
|
|
|
59
60
|
formData.append('participant_name', context.participantName);
|
|
60
61
|
}
|
|
61
62
|
try {
|
|
62
|
-
const headers = {};
|
|
63
|
-
if (context.sessionToken) {
|
|
64
|
-
headers['X-Session-Token'] = context.sessionToken;
|
|
65
|
-
}
|
|
66
63
|
const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
|
|
67
64
|
method: 'POST',
|
|
68
|
-
headers,
|
|
65
|
+
headers: (_a = context.headers) !== null && _a !== void 0 ? _a : {},
|
|
69
66
|
body: formData,
|
|
70
67
|
});
|
|
71
68
|
if (!response.ok) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-attachment-manager.js","sourceRoot":"","sources":["../../src/services/file-attachment-manager.ts"],"names":[],"mappings":"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","sourcesContent":["export interface UploadedFile {\n id: number;\n name: string;\n size: number;\n content_type: string;\n}\n\nexport interface SelectedFile {\n file: File;\n uploaded?: UploadedFile;\n error?: string;\n}\n\nexport interface AttachmentValidationConfig {\n supportedExtensions: string[];\n maxFileSizeMb: number;\n maxTotalSizeMb: number;\n}\n\nexport interface UploadContext {\n apiBaseUrl: string;\n sessionId: string;\n participantId: string;\n participantName?: string;\n sessionToken?: string;\n}\n\nexport interface UploadResult {\n selectedFiles: SelectedFile[];\n uploadedIds: number[];\n errorMessage?: string;\n tokenRejected?: boolean;\n}\n\nexport class FileAttachmentManager {\n private readonly supportedExtensions: string[];\n private readonly maxFileSizeMb: number;\n private readonly maxTotalSizeMb: number;\n\n constructor(config: AttachmentValidationConfig) {\n this.supportedExtensions = config.supportedExtensions;\n this.maxFileSizeMb = config.maxFileSizeMb;\n this.maxTotalSizeMb = config.maxTotalSizeMb;\n }\n\n addFiles(existingFiles: SelectedFile[], files: FileList | File[]): SelectedFile[] {\n const newSelected: SelectedFile[] = [];\n const fileArray = Array.from(files instanceof FileList ? Array.from(files) : files);\n let totalSize = existingFiles.reduce((sum, f) => sum + f.file.size, 0);\n\n for (const file of fileArray) {\n const extension = this.getFileExtension(file.name);\n const contentType = file.type.split('/')[0];\n if (contentType != 'text' && !this.supportedExtensions.includes(extension)) {\n newSelected.push({ file, error: `File type ${extension} not supported` });\n continue;\n }\n\n const fileSizeMb = this.bytesToMb(file.size);\n if (fileSizeMb > this.maxFileSizeMb) {\n newSelected.push({ file, error: `File exceeds ${this.maxFileSizeMb}MB limit` });\n continue;\n }\n\n totalSize += file.size;\n const totalSizeMb = this.bytesToMb(totalSize);\n if (totalSizeMb > this.maxTotalSizeMb) {\n newSelected.push({ file, error: `Total size exceeds ${this.maxTotalSizeMb}MB limit` });\n continue;\n }\n\n newSelected.push({ file });\n }\n\n return [...existingFiles, ...newSelected];\n }\n\n removeFile(existingFiles: SelectedFile[], index: number): SelectedFile[] {\n return existingFiles.filter((_, i) => i !== index);\n }\n\n markPendingFilesWithError(existingFiles: SelectedFile[], errorMessage: string): SelectedFile[] {\n return existingFiles.map(file => {\n if (!file.error && !file.uploaded) {\n return { ...file, error: errorMessage };\n }\n return file;\n });\n }\n\n async uploadPendingFiles(existingFiles: SelectedFile[], context: UploadContext): Promise<UploadResult> {\n if (existingFiles.length === 0) {\n return { selectedFiles: existingFiles, uploadedIds: [] };\n }\n\n const uploadCandidates = existingFiles.filter(file => !file.error && !file.uploaded);\n const uploadedIds: number[] = existingFiles.filter(file => file.uploaded).map(file => file.uploaded!.id);\n\n if (uploadCandidates.length === 0) {\n return { selectedFiles: existingFiles, uploadedIds };\n }\n\n const formData = new FormData();\n for (const file of uploadCandidates) {\n formData.append('files', file.file);\n }\n formData.append('participant_remote_id', context.participantId);\n if (context.participantName) {\n formData.append('participant_name', context.participantName);\n }\n\n try {\n const headers: Record<string, string> = {};\n if (context.sessionToken) {\n headers['X-Session-Token'] = context.sessionToken;\n }\n const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {\n method: 'POST',\n headers,\n body: formData,\n });\n\n if (!response.ok) {\n const errorData = await this.safeJson(response);\n const errorMessage = (errorData && typeof errorData === 'object' && 'error' in errorData && (errorData as { error?: string }).error) || 'Failed to upload files';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n tokenRejected: response.status === 403,\n };\n }\n\n const data = await this.safeJson(response);\n if (!data || typeof data !== 'object' || !Array.isArray((data as { files?: unknown }).files)) {\n const errorMessage = 'Unexpected upload response shape';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n };\n }\n\n const uploadedFiles = (data as { files: UploadedFile[] }).files;\n let index = 0;\n const updatedSelected = existingFiles.map(file => {\n if (!file.error && !file.uploaded) {\n const uploaded = uploadedFiles[index];\n index += 1;\n return { ...file, uploaded };\n }\n return file;\n });\n uploadedIds.push(...uploadedFiles.map(file => file.id));\n\n return { selectedFiles: updatedSelected, uploadedIds };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n };\n }\n }\n\n private bytesToMb(bytes: number): number {\n return bytes / (1024 * 1024);\n }\n\n private getFileExtension(filename: string): string {\n const parts = filename.split('.');\n const ext = parts.pop();\n return ext ? `.${ext.toLowerCase()}` : '';\n }\n\n private async safeJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return undefined;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"file-attachment-manager.js","sourceRoot":"","sources":["../../src/services/file-attachment-manager.ts"],"names":[],"mappings":"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","sourcesContent":["export interface UploadedFile {\n id: number;\n name: string;\n size: number;\n content_type: string;\n}\n\nexport interface SelectedFile {\n file: File;\n uploaded?: UploadedFile;\n error?: string;\n}\n\nexport interface AttachmentValidationConfig {\n supportedExtensions: string[];\n maxFileSizeMb: number;\n maxTotalSizeMb: number;\n}\n\nexport interface UploadContext {\n apiBaseUrl: string;\n sessionId: string;\n participantId: string;\n participantName?: string;\n /** Auth headers (session token, CSRF, widget version) — see ChatSessionService.getUploadHeaders. */\n headers?: Record<string, string>;\n}\n\nexport interface UploadResult {\n selectedFiles: SelectedFile[];\n uploadedIds: number[];\n errorMessage?: string;\n tokenRejected?: boolean;\n}\n\nexport class FileAttachmentManager {\n private readonly supportedExtensions: string[];\n private readonly maxFileSizeMb: number;\n private readonly maxTotalSizeMb: number;\n\n constructor(config: AttachmentValidationConfig) {\n this.supportedExtensions = config.supportedExtensions;\n this.maxFileSizeMb = config.maxFileSizeMb;\n this.maxTotalSizeMb = config.maxTotalSizeMb;\n }\n\n addFiles(existingFiles: SelectedFile[], files: FileList | File[]): SelectedFile[] {\n const newSelected: SelectedFile[] = [];\n const fileArray = Array.from(files instanceof FileList ? Array.from(files) : files);\n let totalSize = existingFiles.reduce((sum, f) => sum + f.file.size, 0);\n\n for (const file of fileArray) {\n const extension = this.getFileExtension(file.name);\n const contentType = file.type.split('/')[0];\n if (contentType != 'text' && !this.supportedExtensions.includes(extension)) {\n newSelected.push({ file, error: `File type ${extension} not supported` });\n continue;\n }\n\n const fileSizeMb = this.bytesToMb(file.size);\n if (fileSizeMb > this.maxFileSizeMb) {\n newSelected.push({ file, error: `File exceeds ${this.maxFileSizeMb}MB limit` });\n continue;\n }\n\n totalSize += file.size;\n const totalSizeMb = this.bytesToMb(totalSize);\n if (totalSizeMb > this.maxTotalSizeMb) {\n newSelected.push({ file, error: `Total size exceeds ${this.maxTotalSizeMb}MB limit` });\n continue;\n }\n\n newSelected.push({ file });\n }\n\n return [...existingFiles, ...newSelected];\n }\n\n removeFile(existingFiles: SelectedFile[], index: number): SelectedFile[] {\n return existingFiles.filter((_, i) => i !== index);\n }\n\n markPendingFilesWithError(existingFiles: SelectedFile[], errorMessage: string): SelectedFile[] {\n return existingFiles.map(file => {\n if (!file.error && !file.uploaded) {\n return { ...file, error: errorMessage };\n }\n return file;\n });\n }\n\n async uploadPendingFiles(existingFiles: SelectedFile[], context: UploadContext): Promise<UploadResult> {\n if (existingFiles.length === 0) {\n return { selectedFiles: existingFiles, uploadedIds: [] };\n }\n\n const uploadCandidates = existingFiles.filter(file => !file.error && !file.uploaded);\n const uploadedIds: number[] = existingFiles.filter(file => file.uploaded).map(file => file.uploaded!.id);\n\n if (uploadCandidates.length === 0) {\n return { selectedFiles: existingFiles, uploadedIds };\n }\n\n const formData = new FormData();\n for (const file of uploadCandidates) {\n formData.append('files', file.file);\n }\n formData.append('participant_remote_id', context.participantId);\n if (context.participantName) {\n formData.append('participant_name', context.participantName);\n }\n\n try {\n const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {\n method: 'POST',\n headers: context.headers ?? {},\n body: formData,\n });\n\n if (!response.ok) {\n const errorData = await this.safeJson(response);\n const errorMessage = (errorData && typeof errorData === 'object' && 'error' in errorData && (errorData as { error?: string }).error) || 'Failed to upload files';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n tokenRejected: response.status === 403,\n };\n }\n\n const data = await this.safeJson(response);\n if (!data || typeof data !== 'object' || !Array.isArray((data as { files?: unknown }).files)) {\n const errorMessage = 'Unexpected upload response shape';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n };\n }\n\n const uploadedFiles = (data as { files: UploadedFile[] }).files;\n let index = 0;\n const updatedSelected = existingFiles.map(file => {\n if (!file.error && !file.uploaded) {\n const uploaded = uploadedFiles[index];\n index += 1;\n return { ...file, uploaded };\n }\n return file;\n });\n uploadedIds.push(...uploadedFiles.map(file => file.id));\n\n return { selectedFiles: updatedSelected, uploadedIds };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';\n return {\n selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),\n uploadedIds,\n errorMessage,\n };\n }\n }\n\n private bytesToMb(bytes: number): number {\n return bytes / (1024 * 1024);\n }\n\n private getFileExtension(filename: string): string {\n const parts = filename.split('.');\n const ext = parts.pop();\n return ext ? `.${ext.toLowerCase()}` : '';\n }\n\n private async safeJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return undefined;\n }\n }\n}\n"]}
|
|
@@ -5234,15 +5234,20 @@ class ChatSessionService {
|
|
|
5234
5234
|
}
|
|
5235
5235
|
throw new Error(message);
|
|
5236
5236
|
}
|
|
5237
|
-
|
|
5237
|
+
/** Headers for multipart requests (no Content-Type — fetch sets the boundary). */
|
|
5238
|
+
getUploadHeaders() {
|
|
5238
5239
|
const headers = this.getCommonHeaders();
|
|
5239
|
-
headers['Content-Type'] = 'application/json';
|
|
5240
5240
|
const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
|
|
5241
5241
|
if (csrfToken) {
|
|
5242
5242
|
headers['X-CSRFToken'] = csrfToken;
|
|
5243
5243
|
}
|
|
5244
5244
|
return headers;
|
|
5245
5245
|
}
|
|
5246
|
+
getJsonHeaders() {
|
|
5247
|
+
const headers = this.getUploadHeaders();
|
|
5248
|
+
headers['Content-Type'] = 'application/json';
|
|
5249
|
+
return headers;
|
|
5250
|
+
}
|
|
5246
5251
|
getCommonHeaders() {
|
|
5247
5252
|
const headers = {
|
|
5248
5253
|
'x-ocs-widget-version': this.widgetVersion,
|
|
@@ -5302,6 +5307,7 @@ class FileAttachmentManager {
|
|
|
5302
5307
|
});
|
|
5303
5308
|
}
|
|
5304
5309
|
async uploadPendingFiles(existingFiles, context) {
|
|
5310
|
+
var _a;
|
|
5305
5311
|
if (existingFiles.length === 0) {
|
|
5306
5312
|
return { selectedFiles: existingFiles, uploadedIds: [] };
|
|
5307
5313
|
}
|
|
@@ -5319,13 +5325,9 @@ class FileAttachmentManager {
|
|
|
5319
5325
|
formData.append('participant_name', context.participantName);
|
|
5320
5326
|
}
|
|
5321
5327
|
try {
|
|
5322
|
-
const headers = {};
|
|
5323
|
-
if (context.sessionToken) {
|
|
5324
|
-
headers['X-Session-Token'] = context.sessionToken;
|
|
5325
|
-
}
|
|
5326
5328
|
const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
|
|
5327
5329
|
method: 'POST',
|
|
5328
|
-
headers,
|
|
5330
|
+
headers: (_a = context.headers) !== null && _a !== void 0 ? _a : {},
|
|
5329
5331
|
body: formData,
|
|
5330
5332
|
});
|
|
5331
5333
|
if (!response.ok) {
|
|
@@ -5879,7 +5881,7 @@ const OcsChat = /*@__PURE__*/ proxyCustomElement(class OcsChat extends HTMLEleme
|
|
|
5879
5881
|
sessionId: this.activeSessionId,
|
|
5880
5882
|
participantId: this.getOrGenerateUserId(),
|
|
5881
5883
|
participantName: this.userName,
|
|
5882
|
-
|
|
5884
|
+
headers: this.getChatService().getUploadHeaders(),
|
|
5883
5885
|
});
|
|
5884
5886
|
this.selectedFiles = uploadResult.selectedFiles;
|
|
5885
5887
|
if (uploadResult.tokenRejected) {
|