open-chat-studio-widget 0.4.8 → 0.5.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.
Files changed (51) hide show
  1. package/README.md +23 -20
  2. package/dist/cjs/{index-AhSI5tER.js → index-Du0PBL6n.js} +4 -2
  3. package/dist/cjs/index-Du0PBL6n.js.map +1 -0
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/open-chat-studio-widget.cjs.entry.js +1116 -301
  6. package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
  7. package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
  8. package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
  9. package/dist/collection/components/ocs-chat/{heroicons.js → icons.js} +23 -1
  10. package/dist/collection/components/ocs-chat/icons.js.map +1 -0
  11. package/dist/collection/components/ocs-chat/ocs-chat.css +596 -1983
  12. package/dist/collection/components/ocs-chat/ocs-chat.js +480 -273
  13. package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
  14. package/dist/collection/services/chat-session-service.js +145 -0
  15. package/dist/collection/services/chat-session-service.js.map +1 -0
  16. package/dist/collection/services/file-attachment-manager.js +125 -0
  17. package/dist/collection/services/file-attachment-manager.js.map +1 -0
  18. package/dist/collection/utils/cookies.js +5 -12
  19. package/dist/collection/utils/cookies.js.map +1 -1
  20. package/dist/collection/utils/markdown.js +1 -1
  21. package/dist/collection/utils/markdown.js.map +1 -1
  22. package/dist/collection/utils/translations.js +99 -0
  23. package/dist/collection/utils/translations.js.map +1 -0
  24. package/dist/components/open-chat-studio-widget.js +1122 -302
  25. package/dist/components/open-chat-studio-widget.js.map +1 -1
  26. package/dist/esm/{index-DkJ7OJTS.js → index-CX3v6rTy.js} +4 -3
  27. package/dist/esm/index-CX3v6rTy.js.map +1 -0
  28. package/dist/esm/loader.js +3 -3
  29. package/dist/esm/open-chat-studio-widget.entry.js +1116 -301
  30. package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
  31. package/dist/esm/open-chat-studio-widget.js +3 -3
  32. package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
  33. package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
  34. package/dist/open-chat-studio-widget/p-90719a8b.entry.js +4 -0
  35. package/dist/open-chat-studio-widget/p-90719a8b.entry.js.map +1 -0
  36. package/dist/open-chat-studio-widget/p-CX3v6rTy.js +3 -0
  37. package/dist/open-chat-studio-widget/p-CX3v6rTy.js.map +1 -0
  38. package/dist/types/components/ocs-chat/{heroicons.d.ts → icons.d.ts} +19 -0
  39. package/dist/types/components/ocs-chat/ocs-chat.d.ts +52 -36
  40. package/dist/types/components.d.ts +22 -8
  41. package/dist/types/services/chat-session-service.d.ts +78 -0
  42. package/dist/types/services/file-attachment-manager.d.ts +40 -0
  43. package/dist/types/utils/translations.d.ts +23 -0
  44. package/package.json +8 -3
  45. package/dist/cjs/index-AhSI5tER.js.map +0 -1
  46. package/dist/collection/components/ocs-chat/heroicons.js.map +0 -1
  47. package/dist/esm/index-DkJ7OJTS.js.map +0 -1
  48. package/dist/open-chat-studio-widget/p-DkJ7OJTS.js +0 -3
  49. package/dist/open-chat-studio-widget/p-DkJ7OJTS.js.map +0 -1
  50. package/dist/open-chat-studio-widget/p-bde68fbd.entry.js +0 -4
  51. package/dist/open-chat-studio-widget/p-bde68fbd.entry.js.map +0 -1
@@ -1,26 +1,6 @@
1
- interface ChatMessage {
2
- created_at: string;
3
- role: 'system' | 'user' | 'assistant';
4
- content: string;
5
- metadata?: any;
6
- attachments?: ChatAttachment[];
7
- }
8
- interface ChatAttachment {
9
- name: string;
10
- content_type: string;
11
- size: number;
12
- }
13
- interface UploadedFile {
14
- id: number;
15
- name: string;
16
- size: number;
17
- content_type: string;
18
- }
19
- interface SelectedFile {
20
- file: File;
21
- uploaded?: UploadedFile;
22
- error?: string;
23
- }
1
+ import { TranslationManager } from '../../utils/translations';
2
+ import { ChatMessage } from '../../services/chat-session-service';
3
+ import { SelectedFile } from '../../services/file-attachment-manager';
24
4
  export declare class OcsChat {
25
5
  private static readonly TASK_POLLING_MAX_ATTEMPTS;
26
6
  private static readonly TASK_POLLING_INTERVAL_MS;
@@ -38,7 +18,7 @@ export declare class OcsChat {
38
18
  */
39
19
  chatbotId: string;
40
20
  /**
41
- * The base URL for the API (defaults to current origin).
21
+ * The base URL for the API.
42
22
  */
43
23
  apiBaseUrl?: string;
44
24
  /**
@@ -49,6 +29,10 @@ export declare class OcsChat {
49
29
  * URL of the icon to display on the button. If not provided, uses the default OCS logo.
50
30
  */
51
31
  iconUrl?: string;
32
+ /**
33
+ * Authentication key for embedded channels
34
+ */
35
+ embedKey?: string;
52
36
  /**
53
37
  * The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
54
38
  */
@@ -106,6 +90,11 @@ export declare class OcsChat {
106
90
  * The text to display while the assistant is typing/preparing a response.
107
91
  */
108
92
  typingIndicatorText?: string;
93
+ /**
94
+ * The language code for the widget UI (e.g., 'en', 'es', 'fr'). Defaults to en
95
+ */
96
+ language?: string;
97
+ translationsUrl?: string;
109
98
  error: string;
110
99
  messages: ChatMessage[];
111
100
  sessionId?: string;
@@ -132,37 +121,45 @@ export declare class OcsChat {
132
121
  showNewChatConfirmation: boolean;
133
122
  selectedFiles: SelectedFile[];
134
123
  isUploadingFiles: boolean;
135
- private pollingIntervalRef?;
124
+ private buttonPosition;
125
+ private buttonHorizontalSide;
126
+ private buttonVerticalSide;
127
+ isButtonDragging: boolean;
128
+ buttonWasDragged: boolean;
129
+ translationManager: TranslationManager;
130
+ private chatService?;
131
+ private messagePollingHandle?;
132
+ private taskPollingHandle?;
133
+ private attachmentManager;
136
134
  private messageListRef?;
137
135
  private textareaRef?;
138
136
  private chatWindowRef?;
139
137
  private fileInputRef?;
138
+ private buttonRef?;
139
+ private buttonDragOffset;
140
+ private rafId;
141
+ private buttonListenersAttached;
140
142
  private chatWindowHeight;
141
143
  private chatWindowWidth;
142
144
  private chatWindowFullscreenWidth;
143
145
  private positionInitialized;
144
146
  host: HTMLElement;
145
- componentWillLoad(): void;
147
+ componentWillLoad(): Promise<void>;
146
148
  componentDidLoad(): void;
147
149
  disconnectedCallback(): void;
150
+ private getChatService;
148
151
  private addErrorMessage;
149
152
  private handleError;
150
153
  private parseJSONProp;
151
154
  private parseWelcomeMessages;
152
155
  private parseStarterQuestions;
156
+ private initializeTranslations;
157
+ private loadTranslationsFromUrl;
153
158
  private cleanup;
154
- private getApiBaseUrl;
155
- private getApiHeaders;
156
159
  private startSession;
157
- private markPendingFilesWithError;
158
160
  private uploadFiles;
159
161
  private sendMessage;
160
162
  private handleStarterQuestionClick;
161
- private pollTaskResponse;
162
- private startPolling;
163
- private pauseMessagePolling;
164
- private resumeMessagePolling;
165
- private pollForMessages;
166
163
  /**
167
164
  * Scroll the message container to the bottom.
168
165
  * @param forceEnd When `false`, scroll the top of the last message into view.
@@ -183,6 +180,9 @@ export declare class OcsChat {
183
180
  * @param visible - The new value for the field.
184
181
  */
185
182
  visibilityHandler(visible: boolean): Promise<void>;
183
+ private startTaskPolling;
184
+ private startMessagePolling;
185
+ private stopMessagePolling;
186
186
  setPosition(position: 'left' | 'center' | 'right'): void;
187
187
  getPositionClasses(): string;
188
188
  private getFullscreenBounds;
@@ -209,7 +209,24 @@ export declare class OcsChat {
209
209
  private handleTouchMove;
210
210
  private handleTouchEnd;
211
211
  private handleWindowResize;
212
- private getDefaultIconUrl;
212
+ private initializeButtonPosition;
213
+ private updateHostPosition;
214
+ private isButtonDraggable;
215
+ private handleButtonMouseDown;
216
+ private handleButtonTouchStart;
217
+ private handleButtonMouseMove;
218
+ private handleButtonTouchMove;
219
+ private updateButtonPosition;
220
+ private handleButtonMouseUp;
221
+ private handleButtonTouchEnd;
222
+ private handleButtonClick;
223
+ private addButtonEventListeners;
224
+ private removeButtonEventListeners;
225
+ private isAutoPosition;
226
+ private parsePixelValue;
227
+ private getNumericPositionValue;
228
+ private getWelcomeMessages;
229
+ private getStarterQuestions;
213
230
  private getButtonClasses;
214
231
  private renderButton;
215
232
  private getStorageKeys;
@@ -225,4 +242,3 @@ export declare class OcsChat {
225
242
  private toggleFullscreen;
226
243
  render(): any;
227
244
  }
228
- export {};
@@ -18,8 +18,8 @@ export namespace Components {
18
18
  */
19
19
  "allowFullScreen": boolean;
20
20
  /**
21
- * The base URL for the API (defaults to current origin).
22
- * @default "https://chatbots.dimagi.com"
21
+ * The base URL for the API.
22
+ * @default "https://www.openchatstudio.com"
23
23
  */
24
24
  "apiBaseUrl"?: string;
25
25
  /**
@@ -35,6 +35,10 @@ export namespace Components {
35
35
  * The ID of the chatbot to connect to.
36
36
  */
37
37
  "chatbotId": string;
38
+ /**
39
+ * Authentication key for embedded channels
40
+ */
41
+ "embedKey"?: string;
38
42
  /**
39
43
  * The text to place in the header.
40
44
  */
@@ -43,9 +47,12 @@ export namespace Components {
43
47
  * URL of the icon to display on the button. If not provided, uses the default OCS logo.
44
48
  */
45
49
  "iconUrl"?: string;
50
+ /**
51
+ * The language code for the widget UI (e.g., 'en', 'es', 'fr'). Defaults to en
52
+ */
53
+ "language"?: string;
46
54
  /**
47
55
  * The message to display in the new chat confirmation dialog.
48
- * @default "Starting a new chat will clear your current conversation. Continue?"
49
56
  */
50
57
  "newChatConfirmationMessage"?: string;
51
58
  /**
@@ -67,9 +74,9 @@ export namespace Components {
67
74
  * Array of starter questions that users can click to send (JSON array of strings)
68
75
  */
69
76
  "starterQuestions"?: string;
77
+ "translationsUrl"?: string;
70
78
  /**
71
79
  * The text to display while the assistant is typing/preparing a response.
72
- * @default "Preparing response"
73
80
  */
74
81
  "typingIndicatorText"?: string;
75
82
  /**
@@ -115,8 +122,8 @@ declare namespace LocalJSX {
115
122
  */
116
123
  "allowFullScreen"?: boolean;
117
124
  /**
118
- * The base URL for the API (defaults to current origin).
119
- * @default "https://chatbots.dimagi.com"
125
+ * The base URL for the API.
126
+ * @default "https://www.openchatstudio.com"
120
127
  */
121
128
  "apiBaseUrl"?: string;
122
129
  /**
@@ -132,6 +139,10 @@ declare namespace LocalJSX {
132
139
  * The ID of the chatbot to connect to.
133
140
  */
134
141
  "chatbotId": string;
142
+ /**
143
+ * Authentication key for embedded channels
144
+ */
145
+ "embedKey"?: string;
135
146
  /**
136
147
  * The text to place in the header.
137
148
  */
@@ -140,9 +151,12 @@ declare namespace LocalJSX {
140
151
  * URL of the icon to display on the button. If not provided, uses the default OCS logo.
141
152
  */
142
153
  "iconUrl"?: string;
154
+ /**
155
+ * The language code for the widget UI (e.g., 'en', 'es', 'fr'). Defaults to en
156
+ */
157
+ "language"?: string;
143
158
  /**
144
159
  * The message to display in the new chat confirmation dialog.
145
- * @default "Starting a new chat will clear your current conversation. Continue?"
146
160
  */
147
161
  "newChatConfirmationMessage"?: string;
148
162
  /**
@@ -164,9 +178,9 @@ declare namespace LocalJSX {
164
178
  * Array of starter questions that users can click to send (JSON array of strings)
165
179
  */
166
180
  "starterQuestions"?: string;
181
+ "translationsUrl"?: string;
167
182
  /**
168
183
  * The text to display while the assistant is typing/preparing a response.
169
- * @default "Preparing response"
170
184
  */
171
185
  "typingIndicatorText"?: string;
172
186
  /**
@@ -0,0 +1,78 @@
1
+ export type ChatRole = 'system' | 'user' | 'assistant';
2
+ export interface ChatAttachment {
3
+ name: string;
4
+ content_type: string;
5
+ size: number;
6
+ }
7
+ export interface ChatMessage {
8
+ created_at: string;
9
+ role: ChatRole;
10
+ content: string;
11
+ metadata?: unknown;
12
+ attachments?: ChatAttachment[];
13
+ }
14
+ export interface ChatStartSessionResponse {
15
+ session_id: string;
16
+ chatbot: unknown;
17
+ participant: unknown;
18
+ seed_message_task_id?: string;
19
+ }
20
+ export interface ChatSendMessageResponse {
21
+ task_id: string;
22
+ status: 'processing' | 'completed' | 'error';
23
+ error?: string;
24
+ }
25
+ export interface ChatTaskPollResponse {
26
+ message?: ChatMessage;
27
+ status: 'processing' | 'complete';
28
+ error?: string;
29
+ }
30
+ export interface ChatPollResponse {
31
+ messages: ChatMessage[];
32
+ has_more: boolean;
33
+ session_status: 'active' | 'ended';
34
+ }
35
+ export interface ChatSessionServiceOptions {
36
+ apiBaseUrl: string;
37
+ embedKey?: string;
38
+ widgetVersion: string;
39
+ csrfTokenProvider?: (apiBaseUrl: string) => string | undefined;
40
+ taskPollingIntervalMs?: number;
41
+ taskPollingMaxAttempts?: number;
42
+ messagePollingIntervalMs?: number;
43
+ }
44
+ export interface TaskPollingCallbacks {
45
+ onMessage: (message: ChatMessage) => void;
46
+ onTimeout?: () => void;
47
+ onError?: (error: Error) => void;
48
+ }
49
+ export interface TaskPollingHandle {
50
+ cancel: () => void;
51
+ }
52
+ export interface MessagePollingCallbacks {
53
+ getSince: () => string | undefined;
54
+ onMessages: (messages: ChatMessage[]) => void;
55
+ onError?: (error: Error) => void;
56
+ }
57
+ export interface MessagePollingHandle {
58
+ stop: () => void;
59
+ }
60
+ export declare class ChatSessionService {
61
+ private readonly apiBaseUrl;
62
+ private readonly embedKey?;
63
+ private readonly widgetVersion;
64
+ private readonly csrfTokenProvider;
65
+ private readonly taskPollingIntervalMs;
66
+ private readonly taskPollingMaxAttempts;
67
+ private readonly messagePollingIntervalMs;
68
+ private messagePollingTimer?;
69
+ constructor(options: ChatSessionServiceOptions);
70
+ startSession(requestBody: Record<string, unknown>): Promise<ChatStartSessionResponse>;
71
+ sendMessage(sessionId: string, payload: Record<string, unknown>): Promise<ChatSendMessageResponse>;
72
+ pollTaskOnce(sessionId: string, taskId: string): Promise<ChatTaskPollResponse>;
73
+ pollTask(sessionId: string, taskId: string, callbacks: TaskPollingCallbacks): TaskPollingHandle;
74
+ fetchMessages(sessionId: string, since?: string): Promise<ChatPollResponse>;
75
+ startMessagePolling(sessionId: string, callbacks: MessagePollingCallbacks): MessagePollingHandle;
76
+ stopMessagePolling(): void;
77
+ private getJsonHeaders;
78
+ }
@@ -0,0 +1,40 @@
1
+ export interface UploadedFile {
2
+ id: number;
3
+ name: string;
4
+ size: number;
5
+ content_type: string;
6
+ }
7
+ export interface SelectedFile {
8
+ file: File;
9
+ uploaded?: UploadedFile;
10
+ error?: string;
11
+ }
12
+ export interface AttachmentValidationConfig {
13
+ supportedExtensions: string[];
14
+ maxFileSizeMb: number;
15
+ maxTotalSizeMb: number;
16
+ }
17
+ export interface UploadContext {
18
+ apiBaseUrl: string;
19
+ sessionId: string;
20
+ participantId: string;
21
+ participantName?: string;
22
+ }
23
+ export interface UploadResult {
24
+ selectedFiles: SelectedFile[];
25
+ uploadedIds: number[];
26
+ errorMessage?: string;
27
+ }
28
+ export declare class FileAttachmentManager {
29
+ private readonly supportedExtensions;
30
+ private readonly maxFileSizeMb;
31
+ private readonly maxTotalSizeMb;
32
+ constructor(config: AttachmentValidationConfig);
33
+ addFiles(existingFiles: SelectedFile[], files: FileList | File[]): SelectedFile[];
34
+ removeFile(existingFiles: SelectedFile[], index: number): SelectedFile[];
35
+ markPendingFilesWithError(existingFiles: SelectedFile[], errorMessage: string): SelectedFile[];
36
+ uploadPendingFiles(existingFiles: SelectedFile[], context: UploadContext): Promise<UploadResult>;
37
+ private bytesToMb;
38
+ private getFileExtension;
39
+ private safeJson;
40
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Translation utilities for the chat widget
3
+ */
4
+ import en from '../assets/translations/en.json';
5
+ export type TranslationStrings = typeof en;
6
+ export declare const defaultTranslations: TranslationStrings;
7
+ export declare function getBrowserLanguage(): string;
8
+ export declare function resolveLanguage(langProp?: string): string;
9
+ export declare function loadTranslations(language: string): Promise<TranslationStrings>;
10
+ /**
11
+ * Overrides matching keys
12
+ */
13
+ export declare function mergeTranslations(baseTranslations: TranslationStrings, customTranslations: Partial<TranslationStrings>): TranslationStrings;
14
+ export declare class TranslationManager {
15
+ private translations;
16
+ private language;
17
+ constructor(language?: string, customTranslations?: Partial<TranslationStrings>);
18
+ private loadTranslations;
19
+ get(key: keyof TranslationStrings, override?: string | null): string | undefined;
20
+ getAll(): TranslationStrings;
21
+ getArray(key: keyof TranslationStrings): string[];
22
+ getLanguage(): string;
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-chat-studio-widget",
3
- "version": "0.4.8",
3
+ "version": "0.5.1",
4
4
  "description": "Chat component for Open Chat Studio",
5
5
  "main": "dist/index.cjs.js",
6
6
  "exports": "./dist/esm/open-chat-studio-widget.js",
@@ -20,13 +20,16 @@
20
20
  "loader/"
21
21
  ],
22
22
  "scripts": {
23
+ "test": "stencil test --spec",
23
24
  "build": "stencil build --docs",
24
25
  "start": "stencil build --dev --watch --serve",
25
26
  "generate": "stencil generate",
26
27
  "use:npmReadme": "mv 'README.md' 'git.README.md' && cp 'src/components/ocs-chat/readme.md' 'README.md'",
27
28
  "use:gitReadme": "mv 'git.README.md' 'README.md'",
28
29
  "prepublishOnly": "run-s build use:npmReadme",
29
- "postpublish": "npm run use:gitReadme"
30
+ "postpublish": "npm run use:gitReadme",
31
+ "type-check": "tsc --noEmit",
32
+ "lint": "eslint --fix src"
30
33
  },
31
34
  "dependencies": {
32
35
  "@stencil/core": "^4.27.0",
@@ -37,6 +40,7 @@
37
40
  },
38
41
  "devDependencies": {
39
42
  "@stencil-community/postcss": "^2.2.0",
43
+ "@tailwindcss/postcss": "^4.1.12",
40
44
  "@tailwindcss/typography": "^0.5.16",
41
45
  "@types/jest": "^29.5.14",
42
46
  "@types/node": "^22.13.4",
@@ -46,7 +50,8 @@
46
50
  "npm-run-all": "^4.1.5",
47
51
  "postcss-import": "^16.1.0",
48
52
  "puppeteer": "^24.2.0",
49
- "tailwindcss": "^3.4.17",
53
+ "stencil-tailwind-plugin": "^2.0.5",
54
+ "tailwindcss": "^4.1.12",
50
55
  "typescript": "^5.7.3"
51
56
  },
52
57
  "license": "MIT"