@nimbusai/webchat-sdk 1.0.0

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 ADDED
@@ -0,0 +1,888 @@
1
+ # Nimbus WebChat SDK
2
+
3
+ A modern, embeddable WebChat SDK with Shadow DOM isolation and real-time WebSocket messaging. Built with TypeScript, Tailwind CSS, and Lucide icons.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40nimbus%2Fwebchat-sdk.svg)](https://badge.fury.io/js/%40nimbus%2Fwebchat-sdk)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript 5.7](https://img.shields.io/badge/typescript-5.7-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
8
+ [![Tailwind CSS 3.4](https://img.shields.io/badge/tailwindcss-3.4-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
9
+ [![Shadow DOM](https://img.shields.io/badge/shadow_dom-isolated-8B5CF6)](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)
10
+
11
+ ---
12
+
13
+ ## Screenshots
14
+
15
+ ### Full Dashboard View
16
+ <p align="center">
17
+ <img src="screenshoots/full-screen.png" alt="Full Application Dashboard" width="800">
18
+ </p>
19
+
20
+ ### Theme Variations
21
+ <p align="center">
22
+ <img src="screenshoots/welcome-message.png" alt="Light Theme - Welcome Message" width="300">
23
+ &nbsp;&nbsp;&nbsp;&nbsp;
24
+ <img src="screenshoots/black-edition.png" alt="Dark Theme - Black Edition" width="300">
25
+ </p>
26
+
27
+ ### Layout Options
28
+ <p align="center">
29
+ <img src="screenshoots/bottom.png" alt="Bottom Position with Typing Indicator" width="300">
30
+ &nbsp;&nbsp;&nbsp;&nbsp;
31
+ <img src="screenshoots/sidepanel.png" alt="Sidepanel Integration" width="300">
32
+ </p>
33
+
34
+ ### File Upload & Media Handling
35
+ <p align="center">
36
+ <img src="screenshoots/send-json.png" alt="JSON Data Exchange" width="300">
37
+ &nbsp;&nbsp;&nbsp;&nbsp;
38
+ <img src="screenshoots/describe-pictures.png" alt="AI Image Description" width="300">
39
+ </p>
40
+
41
+ <p align="center">
42
+ <img src="screenshoots/max-size.png" alt="File Size Limit" width="300">
43
+ &nbsp;&nbsp;&nbsp;&nbsp;
44
+ <img src="screenshoots/uploaded-file-preview.png" alt="File Preview" width="300">
45
+ </p>
46
+
47
+ ## Features
48
+
49
+ - **Zero dependencies** (except Lucide icons)
50
+ - **Fully customizable** UI and theming
51
+ - **Responsive design** with mobile support
52
+ - **Shadow DOM isolation** prevents CSS conflicts
53
+ - **Real-time WebSocket** messaging
54
+ - **TypeScript support** with full type definitions
55
+ - **Multiple formats** (ESM, CommonJS, UMD)
56
+ - **Flexible icons** (Lucide icons or custom images)
57
+ - **Automatic reconnection** with configurable retries
58
+ - **Optional message history** loading with resume conversation
59
+ - **Multiple layouts** (floating popup or sidepanel)
60
+ - **File upload support** with image previews (config-driven)
61
+ - **Character limits** with counter display
62
+ - **Developer-friendly** debug mode and logging
63
+
64
+ ## Tech Stack
65
+
66
+ | Technology | Version | Purpose |
67
+ |---|---|---|
68
+ | [TypeScript](https://www.typescriptlang.org/) | `^5.7.2` | Type-safe development |
69
+ | [Tailwind CSS](https://tailwindcss.com/) | `^3.4.17` | Utility-first styling (pre-compiled into Shadow DOM) |
70
+ | [tsup](https://tsup.egoist.dev/) | `^8.3.5` | Bundler (ESM + CJS + IIFE) |
71
+ | [PostCSS](https://postcss.org/) | `^8.4.49` | CSS processing |
72
+ | [Autoprefixer](https://github.com/postcss/autoprefixer) | `^10.4.20` | Vendor prefix automation |
73
+ | [Vitest](https://vitest.dev/) | `^2.1.8` | Unit testing |
74
+ | [Lucide](https://lucide.dev/) | inline SVGs | Icons (Shadow DOM compatible) |
75
+
76
+ ## Installation
77
+
78
+ ### npm / yarn / pnpm
79
+
80
+ ```bash
81
+ npm install @nimbusai/webchat-sdk
82
+ # or
83
+ yarn add @nimbusai/webchat-sdk
84
+ # or
85
+ pnpm add @nimbusai/webchat-sdk
86
+ ```
87
+
88
+ ```typescript
89
+ import { NimbusChat } from "@nimbusai/webchat-sdk";
90
+
91
+ const chat = new NimbusChat({
92
+ agent_id: "550e8400-e29b-41d4-a716-446655440000",
93
+ });
94
+
95
+ chat.open();
96
+ ```
97
+
98
+ ### CDN (script tag)
99
+
100
+ ```html
101
+ <script src="https://cdn.nimbus.ai/sdk/nimbus-chat.umd.global.js"></script>
102
+ <script>
103
+ NimbusChat.init({
104
+ agent_id: "550e8400-e29b-41d4-a716-446655440000",
105
+ });
106
+ </script>
107
+ ```
108
+
109
+ The CDN bundle exposes a global `NimbusChat` object with a singleton `init()` method — safe to call multiple times.
110
+
111
+ ## Quick Start
112
+
113
+ ```typescript
114
+ const chat = new NimbusChat({
115
+ agent_id: "550e8400-e29b-41d4-a716-446655440000",
116
+ style: { position: "bottom-right" }
117
+ });
118
+ ```
119
+
120
+ The widget renders a floating chat bubble in the corner of the page. Click it to open the chat panel. The WebSocket connection is established lazily — only when the user opens the chat for the first time.
121
+
122
+ ## API Reference
123
+
124
+ ### Initialization
125
+
126
+ ```javascript
127
+ // NPM usage
128
+ const chat = new NimbusChat(config);
129
+
130
+ // CDN usage
131
+ const chat = NimbusChat.init(config);
132
+ ```
133
+
134
+ ### Methods
135
+
136
+ | Method | Description |
137
+ |--------|-------------|
138
+ | `chat.open()` | Show the chat widget |
139
+ | `chat.close()` | Hide the chat widget |
140
+ | `chat.toggle()` | Toggle chat widget visibility |
141
+ | `chat.destroy()` | Remove the widget from DOM completely |
142
+
143
+ ---
144
+
145
+ ## Configuration Reference
146
+
147
+ The SDK provides extensive configuration options to customize every aspect of the chat widget. All properties are optional except `agent_id`.
148
+
149
+ ### Required Configuration
150
+
151
+ | Property | Type | Description |
152
+ |----------|------|-------------|
153
+ | `agent_id` | `string` | **Required** - Your agent ID (UUID) |
154
+
155
+ ### Core Settings
156
+
157
+ | Property | Type | Default | Description |
158
+ |----------|------|---------|-------------|
159
+ | `dns` | `string` | `"api.nimbus.ai/api/v1/webchat"` | API endpoint for chat services |
160
+ | `resumeConversation` | `boolean` | `false` | When `true`, loads message history on reconnect and shows the "Show More" button. When `false`, starts fresh each time (flow_id is still reused). |
161
+ | `messagesPerPage` | `number` | `10` | Number of messages to load per page when scrolling history |
162
+ | `debug` | `boolean` | `false` | Enable debug logging to console |
163
+ | `allowNewChat` | `boolean` | `false` | Show "New Chat" button in header |
164
+
165
+ ### Style Configuration
166
+
167
+ Controls layout, dimensions, and visual appearance of the widget:
168
+
169
+ ```javascript
170
+ style: {
171
+ position: "bottom-right",
172
+ width: "380px", // CSS width string (e.g. "380px", "100%")
173
+ height: "560px", // CSS height string (window mode only)
174
+ font: '"Inter Variable", sans-serif', // Global font family override
175
+ background: "#ffffff", // CSS color or image URL
176
+ mobile: {
177
+ position: "bottom-right", // Override position on mobile devices
178
+ breakpoint: "480px" // Viewport width to trigger mobile mode
179
+ }
180
+ }
181
+ ```
182
+
183
+ | Property | Type | Default | Description |
184
+ |----------|------|---------|-------------|
185
+ | `style.position` | `ChatPosition` | `"bottom-right"` | Widget position on page. <br>Options: `"bottom-right"`, `"bottom-left"`, `"sidepanel-left"`, `"sidepanel-right"` |
186
+ | `style.width` | `string` | `"380px"` | Chat window width (CSS value) |
187
+ | `style.height` | `string` | `"560px"` | Chat window height (CSS value, window mode only) |
188
+ | `style.font` | `string` | System font | Global font family override |
189
+ | `style.background` | `string` | `"#f3f1ef"` | Chat body background (CSS color or image URL) |
190
+ | `style.mobile.position` | `ChatPosition` | Same as `style.position` | Widget position on mobile devices |
191
+ | `style.mobile.breakpoint` | `string` | `undefined` | Viewport width breakpoint for mobile mode (e.g. `"480px"`) |
192
+
193
+ ### Theme Configuration
194
+
195
+ Global theme colors used throughout the widget:
196
+
197
+ ```javascript
198
+ theme: {
199
+ primary: "#ffce1c", // Primary color (buttons, headers, bubbles)
200
+ secondary: "#f3f1ef" // Secondary color (text, icons on primary bg)
201
+ }
202
+ ```
203
+
204
+ ### Chat Bubble Settings
205
+
206
+ The floating trigger button that opens/closes the chat:
207
+
208
+ ```javascript
209
+ bubble: {
210
+ position: "bottom-right",
211
+ autoHide: false, // Hide bubble when chat is open
212
+ icon: {
213
+ img: "message-circle", // Lucide icon or image URL
214
+ size: { width: 35, height: 35 }
215
+ }
216
+ }
217
+ ```
218
+
219
+ | Property | Type | Default | Description |
220
+ |----------|------|---------|-------------|
221
+ | `position` | `BubblePosition` | `"bottom-right"` | Bubble position. <br>Options: `"bottom-right"`, `"bottom-left"` |
222
+ | `autoHide` | `boolean` | `false` | Hide the bubble when the chat panel is open |
223
+ | `icon` | `IconConfig \| null` | Default Lucide icon | Custom icon for the bubble |
224
+
225
+ ### Header Configuration
226
+
227
+ ```javascript
228
+ header: {
229
+ icon: {
230
+ img: "https://example.com/logo.svg", // Custom image URL or Lucide icon
231
+ size: { width: 125, height: 19 }
232
+ },
233
+ text: {
234
+ value: "Support Chat",
235
+ color: "#1e293b",
236
+ font: "Inter",
237
+ },
238
+ color: {
239
+ primary: "#f3f1ef", // Header background color
240
+ secondary: "#ffce1c" // Close button icon color
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### Welcome Message
246
+
247
+ Shown when chat is empty, automatically hidden after first message:
248
+
249
+ ```javascript
250
+ welcome: {
251
+ display: true, // Show/hide welcome message
252
+ preTitle: {
253
+ value: "Welcome to :",
254
+ text: { color: "#1e293b", font: "" }
255
+ },
256
+ title: {
257
+ value: " Nimbus Chat!",
258
+ text: { color: "#1e293b", font: "" }
259
+ },
260
+ subtitle: {
261
+ value: "Send a message to start a conversation",
262
+ text: { color: "gray", font: "" }
263
+ }
264
+ }
265
+ ```
266
+
267
+ ### Message Styling
268
+
269
+ Configure user and bot message bubbles independently:
270
+
271
+ ```javascript
272
+ userMessage: {
273
+ background: "#DCF8C6",
274
+ width: "80%", // Max width of message bubble (CSS value). Default: "80%"
275
+ text: {
276
+ color: "#111B21",
277
+ font: "",
278
+ size: 13
279
+ },
280
+ icon: {
281
+ img: "user", // Lucide icon or custom image URL
282
+ size: { width: 20, height: 20 }
283
+ }
284
+ }
285
+
286
+ botMessage: {
287
+ background: "#FFFFFF",
288
+ width: "80%", // Max width of message bubble (CSS value). Default: "80%"
289
+ text: {
290
+ color: "#111B21",
291
+ font: "",
292
+ size: 13
293
+ },
294
+ icon: {
295
+ img: "bot", // Lucide icon or custom image URL
296
+ size: { width: 20, height: 20 }
297
+ }
298
+ }
299
+ ```
300
+
301
+ > **Note**: Set `icon: null` to explicitly hide the avatar. Omit `icon` entirely to use the default.
302
+
303
+ ### Input Configuration
304
+
305
+ ```javascript
306
+ input: {
307
+ placeholder: "Ask Nimbus",
308
+ expandable: true, // Auto-expanding textarea (up to 8 lines)
309
+ text: {
310
+ color: "#1e293b",
311
+ font: "",
312
+ },
313
+ background: {
314
+ primary: "white", // Input field background
315
+ secondary: "#f3f1ef" // Container background
316
+ },
317
+ upload: { // File upload settings (omit or set null to disable)
318
+ maxFileSize: 5242880, // 5MB in bytes
319
+ errorDisplayDuration: 2000, // Error message duration (ms)
320
+ allowedFileTypes: [
321
+ "image/jpeg",
322
+ "image/png",
323
+ "image/gif",
324
+ "application/pdf"
325
+ ],
326
+ icon: {
327
+ img: "paperclip",
328
+ size: { width: 20, height: 20 }
329
+ }
330
+ },
331
+ maxCharacters: { // Character limit with counter
332
+ limit: 10000, // Maximum characters allowed
333
+ text: {
334
+ color: "gray",
335
+ size: 12
336
+ }
337
+ }
338
+ }
339
+ ```
340
+
341
+ > **Note**: File upload is config-driven. Omit the `upload` property or set it to `null` to disable file uploads. Provide an `upload` object to enable the upload button.
342
+
343
+ ### Send Button
344
+
345
+ ```javascript
346
+ sendButton: {
347
+ align: false, // true = input and button on same row
348
+ icon: {
349
+ img: "send", // Lucide icon or custom image URL
350
+ size: { width: 20, height: 20 }
351
+ }
352
+ }
353
+ ```
354
+
355
+ ### Reconnection Settings
356
+
357
+ Control automatic reconnection behavior:
358
+
359
+ ```javascript
360
+ reconnect: {
361
+ attempts: 5, // Maximum reconnection attempts
362
+ timeout: 5000 // Delay between attempts (ms)
363
+ }
364
+ ```
365
+
366
+ ### Wait for Reply Configuration
367
+
368
+ Control message sending while waiting for bot responses. Works independently from the typing indicator.
369
+
370
+ ```javascript
371
+ waitForReply: {
372
+ timeout: 30000, // Max wait time (ms) before allowing next message
373
+ firstReply: false // Wait for bot's first message in new chat
374
+ }
375
+ ```
376
+
377
+ > **Note**: Omit `waitForReply` to disable input blocking entirely.
378
+
379
+ ### Typing Indicator Configuration
380
+
381
+ Show a typing indicator when waiting for bot responses. Independent from `waitForReply` — you can use either or both.
382
+
383
+ ```javascript
384
+ isTypingIndicator: {
385
+ position: "bottom",
386
+ title: {
387
+ value: "AI Assistant is typing...",
388
+ text: {
389
+ color: "#1e293b",
390
+ font: ""
391
+ }
392
+ }
393
+ }
394
+ ```
395
+
396
+ | Property | Type | Default | Description |
397
+ |----------|------|---------|-------------|
398
+ | `position` | `"top" \| "bottom"` | `"top"` | Where to display the indicator. <br>Options: `"top"` (header status area), `"bottom"` (above input area) |
399
+ | `title.value` | `string` | `"AI Assistant is typing..."` | Indicator text |
400
+ | `title.text` | `TextConfig` | `{ color: "#1e293b" }` | Text styling |
401
+
402
+ > **Note**: Omit `isTypingIndicator` to disable the typing indicator.
403
+
404
+ ### Show More Button
405
+
406
+ Configure the "Show More" button for loading message history (only visible when `resumeConversation: true`):
407
+
408
+ ```javascript
409
+ showMore: {
410
+ value: "Show More",
411
+ sticky: true, // Stick to top of message list
412
+ background: "#FFF4CC",
413
+ text: {
414
+ color: "black",
415
+ size: 13
416
+ },
417
+ icon: {
418
+ img: "chevron-down",
419
+ size: { width: 16, height: 16 }
420
+ }
421
+ }
422
+ ```
423
+
424
+ ---
425
+
426
+ ## Icon System
427
+
428
+ The SDK supports two types of icons throughout all configuration:
429
+
430
+ ### Lucide Icons (Recommended)
431
+
432
+ Text-based icon names that render as inline SVG:
433
+
434
+ ```javascript
435
+ icon: {
436
+ img: "message-circle",
437
+ size: { width: 24, height: 24 },
438
+ color: "#ffffff"
439
+ }
440
+ ```
441
+
442
+ **Popular Lucide Icons:**
443
+ - `"message-circle"` - Chat bubble
444
+ - `"send"` - Send arrow
445
+ - `"x"` - Close/X mark
446
+ - `"rotate-cw"` - Refresh/new chat
447
+ - `"chevron-down"` / `"chevron-up"` - Arrows
448
+ - `"user"` - User avatar
449
+ - `"bot"` - Bot avatar
450
+ - `"paperclip"` - File attachment
451
+
452
+ [Browse all 1000+ Lucide icons →](https://lucide.dev/icons/)
453
+
454
+ ### Custom Images
455
+
456
+ URL-based custom images:
457
+
458
+ ```javascript
459
+ icon: {
460
+ img: "https://example.com/logo.png",
461
+ size: { width: 32, height: 32 }
462
+ // color is ignored for image URLs
463
+ }
464
+ ```
465
+
466
+ ### Hiding Icons
467
+
468
+ ```javascript
469
+ icon: null // Explicitly hide the icon
470
+ // or
471
+ // Omit the icon property entirely to use default
472
+ ```
473
+
474
+ ---
475
+
476
+ ## Shared Type Definitions
477
+
478
+ ### TextConfig
479
+
480
+ Used for styling text elements throughout the SDK:
481
+
482
+ ```typescript
483
+ interface TextConfig {
484
+ display?: boolean; // Show/hide text (not used everywhere)
485
+ value?: string; // The text content
486
+ color?: string; // CSS color value
487
+ font?: string; // Font family override
488
+ size?: number; // Font size in pixels
489
+ }
490
+ ```
491
+
492
+ ### IconConfig
493
+
494
+ Used for all icons in the SDK:
495
+
496
+ ```typescript
497
+ interface IconConfig {
498
+ img?: string; // Lucide icon name or image URL
499
+ size?: {
500
+ width: number; // Width in pixels
501
+ height: number; // Height in pixels
502
+ };
503
+ color?: string; // Icon color (CSS color). Only applies to Lucide icons, ignored for image URLs.
504
+ }
505
+ ```
506
+
507
+ ### ColorPair
508
+
509
+ Used for primary/secondary color combinations:
510
+
511
+ ```typescript
512
+ interface ColorPair {
513
+ primary?: string; // Primary color (usually background)
514
+ secondary?: string; // Secondary color (usually foreground)
515
+ }
516
+ ```
517
+
518
+ ---
519
+
520
+ ## Complete Configuration Example
521
+
522
+ ```javascript
523
+ const chat = new NimbusChat({
524
+ // Required
525
+ agent_id: "550e8400-e29b-41d4-a716-446655440000",
526
+
527
+ // Core Settings
528
+ dns: "api.nimbus.ai/api/v1/chat/ws",
529
+ resumeConversation: false,
530
+ messagesPerPage: 10,
531
+ debug: true,
532
+ allowNewChat: true,
533
+
534
+ // Theme
535
+ theme: {
536
+ primary: "#ffce1c",
537
+ secondary: "#f3f1ef"
538
+ },
539
+
540
+ // Style
541
+ style: {
542
+ position: "bottom-right",
543
+ width: "450px",
544
+ height: "500px",
545
+ font: "",
546
+ background: "#f3f1ef",
547
+ mobile: {
548
+ position: "bottom-right",
549
+ breakpoint: "480px"
550
+ }
551
+ },
552
+
553
+ // Chat Bubble
554
+ bubble: {
555
+ position: "bottom-right",
556
+ autoHide: false,
557
+ icon: {
558
+ img: "message-circle",
559
+ size: { width: 35, height: 35 }
560
+ }
561
+ },
562
+
563
+ // Header
564
+ header: {
565
+ icon: {
566
+ img: "https://example.com/logo.svg",
567
+ size: { width: 125, height: 19 }
568
+ },
569
+ text: {
570
+ value: "",
571
+ color: "#1e293b",
572
+ font: "",
573
+ },
574
+ color: {
575
+ primary: "#f3f1ef",
576
+ secondary: "#ffce1c"
577
+ }
578
+ },
579
+
580
+ // Welcome Message
581
+ welcome: {
582
+ display: true,
583
+ preTitle: {
584
+ value: "Welcome to :",
585
+ text: { color: "#1e293b", font: "" }
586
+ },
587
+ title: {
588
+ value: " Nimbus Chat!",
589
+ text: { color: "#1e293b", font: "" }
590
+ },
591
+ subtitle: {
592
+ value: "Send a message to start a conversation",
593
+ text: { color: "gray", font: "" }
594
+ }
595
+ },
596
+
597
+ // Messages
598
+ userMessage: {
599
+ background: "#DCF8C6",
600
+ width: "80%",
601
+ text: { color: "#111B21", font: "", size: 13 },
602
+ icon: {
603
+ img: "user",
604
+ size: { width: 20, height: 20 }
605
+ }
606
+ },
607
+
608
+ botMessage: {
609
+ background: "#FFFFFF",
610
+ width: "80%",
611
+ text: { color: "#111B21", font: "", size: 13 },
612
+ icon: {
613
+ img: "bot",
614
+ size: { width: 20, height: 20 }
615
+ }
616
+ },
617
+
618
+ // Input Area
619
+ input: {
620
+ placeholder: "Ask Nimbus",
621
+ expandable: true,
622
+ text: {
623
+ color: "#1e293b",
624
+ font: "",
625
+ },
626
+ background: {
627
+ primary: "white",
628
+ secondary: "#f3f1ef"
629
+ },
630
+ maxCharacters: {
631
+ limit: 10000,
632
+ text: {
633
+ color: "gray",
634
+ font: "",
635
+ size: 12
636
+ }
637
+ },
638
+ upload: null
639
+ },
640
+
641
+ // Send Button
642
+ sendButton: {
643
+ align: false,
644
+ icon: {
645
+ img: "send",
646
+ size: { width: 20, height: 20 }
647
+ }
648
+ },
649
+
650
+ // Reconnection
651
+ reconnect: {
652
+ attempts: 5,
653
+ timeout: 5000
654
+ },
655
+
656
+ // Wait for Reply
657
+ waitForReply: {
658
+ timeout: 30000,
659
+ firstReply: false
660
+ },
661
+
662
+ // Typing Indicator (independent from waitForReply)
663
+ isTypingIndicator: {
664
+ position: "bottom",
665
+ title: {
666
+ value: "AI Assistant is typing...",
667
+ text: { color: "#1e293b", font: "" }
668
+ }
669
+ },
670
+
671
+ // Show More (only visible when resumeConversation: true)
672
+ showMore: {
673
+ value: "Show More",
674
+ sticky: true,
675
+ background: "#FFF4CC",
676
+ text: {
677
+ color: "black",
678
+ font: "",
679
+ size: 13
680
+ },
681
+ icon: {
682
+ img: "chevron-down",
683
+ size: { width: 16, height: 16 }
684
+ }
685
+ },
686
+ });
687
+ ```
688
+
689
+ ---
690
+
691
+ ## Debug Mode
692
+
693
+ Enable comprehensive logging for development and troubleshooting:
694
+
695
+ ```javascript
696
+ const chat = new NimbusChat({
697
+ agent_id: "your-uuid-here",
698
+ debug: true
699
+ });
700
+ ```
701
+
702
+ **Debug mode provides:**
703
+ - WebSocket connection events
704
+ - Message send/receive logs
705
+ - Session state changes
706
+ - Configuration resolution details
707
+ - Error stack traces
708
+
709
+ ---
710
+
711
+ ## Development
712
+
713
+ ### Prerequisites
714
+
715
+ - Node.js >= 18
716
+ - npm >= 9
717
+
718
+ ### Setup
719
+
720
+ ```bash
721
+ git clone https://github.com/nichemarket/chat-sdk.git
722
+ cd chat-sdk
723
+ npm install
724
+ ```
725
+
726
+ ### Scripts
727
+
728
+ ```bash
729
+ npm run build # Full build (CSS + TypeScript)
730
+ npm run build:css # Compile Tailwind only
731
+ npm run build:ts # Compile TypeScript only
732
+ npm run type-check # Type-check without emitting
733
+ npm run dev # Watch mode
734
+ npm test # Run tests
735
+ npm run test:watch # Watch mode tests
736
+ ```
737
+
738
+ ### Testing
739
+
740
+ The SDK uses [Vitest](https://vitest.dev/) with `jsdom` for unit testing. Tests cover configuration resolution, validation, core modules, UI utilities, and DOM components.
741
+
742
+ ```bash
743
+ npm test # Run all tests
744
+ npm run test:watch # Run in watch mode
745
+ ```
746
+
747
+ **Test suite structure:**
748
+
749
+ | File | Covers |
750
+ |---|---|
751
+ | `tests/types/resolveConfig.test.ts` | Config resolution, defaults, overrides, deep merging |
752
+ | `tests/utils/validateConfig.test.ts` | Required fields, type validation, nested config validation |
753
+ | `tests/core/EventBus.test.ts` | Pub/sub, `on`/`off`/`once`/`emit`, error isolation, typed events |
754
+ | `tests/core/ChatSession.test.ts` | Session ID, messages, history load/merge, dedup, clear |
755
+ | `tests/utils/FileUtils.test.ts` | File size formatting, Base64 conversion |
756
+ | `tests/utils/DOMBuilder.test.ts` | Element creation, props, chaining, append, conditionals, fragments |
757
+ | `tests/ui/ThemeManager.test.ts` | CSS variables, theme colors, backgrounds, fonts, input styles |
758
+ | `tests/utils/IconRenderer.test.ts` | Lucide SVG rendering, URL images, unknown icons, wrapper/simple modes |
759
+
760
+ ### Common Development Commands
761
+
762
+ ```bash
763
+ # Clean installation (recommended for troubleshooting)
764
+ rm -rf node_modules package-lock.json && npm install && npm run build
765
+
766
+ # Fast build and serve for testing
767
+ npm run build && npx http-server -p 8081 -c-1
768
+ ```
769
+
770
+ ### Code Standards
771
+
772
+ **Logging**: Always use the custom logger instead of `console.*` statements:
773
+
774
+ ```typescript
775
+ import { createLogger } from './utils/logger';
776
+
777
+ // For utility files - create logger at top level
778
+ const logger = createLogger('ComponentName');
779
+
780
+ // For classes - create logger in constructor
781
+ class MyComponent {
782
+ private logger: Logger;
783
+
784
+ constructor(debug = false) {
785
+ this.logger = createLogger('MyComponent', debug);
786
+ }
787
+ }
788
+
789
+ // Usage
790
+ logger.info('Info message');
791
+ logger.warn('Warning message');
792
+ logger.error('Error message');
793
+ ```
794
+
795
+ ### Output Files
796
+
797
+ | Format | File | Size |
798
+ |---|---|---|
799
+ | ESM | `dist/index.mjs` | ~48 KB |
800
+ | CJS | `dist/index.js` | ~49 KB |
801
+ | IIFE/UMD | `dist/nimbus-chat.umd.global.js` | ~49 KB |
802
+ | Types | `dist/index.d.ts` | ~8.5 KB |
803
+
804
+ ### Project Structure
805
+
806
+ ```
807
+ chat-sdk/
808
+ ├── src/
809
+ │ ├── core/ # EventBus, ChatSession, WebSocketManager, ApiClient
810
+ │ ├── icons/ # Lucide SVG icon definitions
811
+ │ ├── styles/ # Tailwind globals + compiled CSS
812
+ │ ├── types/ # TypeScript interfaces (config, message)
813
+ │ ├── ui/ # UI components (Header, MessageList, InputArea, etc.)
814
+ │ ├── utils/ # Utilities (logger, validator, parser, etc.)
815
+ │ ├── NimbusChat.ts # Main SDK orchestrator
816
+ │ └── index.ts # Public exports
817
+ ├── examples/
818
+ │ ├── cdn-usage.html # CDN integration example (full config)
819
+ │ ├── cdn-usage-basic.html # CDN integration example (minimal config)
820
+ │ └── cdn-usage-black.html # CDN integration example (dark theme)
821
+ ├── dist/ # Build output
822
+ ├── tsconfig.json
823
+ ├── tsup.config.js
824
+ ├── tailwind.config.js
825
+ ├── postcss.config.js
826
+ └── package.json
827
+ ```
828
+
829
+ ---
830
+
831
+ ## Architecture
832
+
833
+ The SDK uses **Shadow DOM** (open mode) to fully isolate styles from the host page. Tailwind CSS is pre-compiled at build time and injected into the shadow root at runtime alongside CSS custom properties for theming.
834
+
835
+ ### Component Architecture
836
+
837
+ ```
838
+ NimbusChat (orchestrator)
839
+ ├── EventBus (pub/sub messaging)
840
+ ├── ChatSession (message state + history)
841
+ ├── WebSocketManager (connection lifecycle)
842
+ ├── ApiClient (REST API)
843
+ └── UI Components
844
+ ├── ShadowContainer (DOM isolation)
845
+ ├── ThemeManager (CSS custom properties)
846
+ ├── ChatWindow/SidepanelWindow (containers)
847
+ ├── Header
848
+ ├── MessageList
849
+ ├── InputArea (with FileUpload)
850
+ ├── MessageBubble
851
+ └── ChatBubble (floating trigger)
852
+ ```
853
+
854
+ ### Connection Lifecycle
855
+
856
+ 1. **Initial Connection**: Client opens WebSocket with `agent_id` (and `flow_id` if available from localStorage)
857
+ 2. **Connected**: Server responds with `{ "type": "connected", "flow_id": "uuid" }`
858
+ 3. **Persistence**: `flow_id` is always stored in localStorage and reused on reconnect
859
+ 4. **History Loading**: If `resumeConversation: true`, fetches message history via REST API after connection
860
+ 5. **Messaging**: Simple message exchange with `direction: "inbound"` (user) and `direction: "outbound"` (bot)
861
+
862
+ ### WebSocket Events
863
+
864
+ **Incoming:**
865
+ - `connected` - Connection established, provides `flow_id`
866
+ - `message` - New message from server (`direction: "outbound"`)
867
+
868
+ **Outgoing:**
869
+ - `message` - User message (`direction: "inbound"`)
870
+
871
+ ### Message Schema
872
+
873
+ ```javascript
874
+ // User message (sent to server)
875
+ { "type": "message", "direction": "inbound", "content": "Hello!" }
876
+
877
+ // Bot message (received from server)
878
+ { "type": "message", "direction": "outbound", "content": "Hi there!" }
879
+
880
+ // Connected event (received from server)
881
+ { "type": "connected", "flow_id": "550e8400-e29b-41d4-a716-446655440000" }
882
+ ```
883
+
884
+ ---
885
+
886
+ ## License
887
+
888
+ [MIT](LICENSE)