@nabeh/chat-widget 0.1.0 → 0.1.2

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 CHANGED
@@ -1,280 +1,46 @@
1
- # Chat Widget Library
1
+ # @nabeh/chat-widget
2
2
 
3
- Production-oriented TypeScript library for embedding an AI chat assistant into an Angular website or any browser-based application.
3
+ Embeddable AI chat widget for Angular and other web applications.
4
4
 
5
- ## Publish to npm
6
-
7
- This package is configured for the npm organization scope `@nabeh` and for public publishing.
8
-
9
- ### 1. Sign in with the CTO npm account
10
-
11
- If the CTO does not already have an npm account, create one first at `https://www.npmjs.com/signup`, then sign in.
12
-
13
- ### 2. Create the npm organization
14
-
15
- While signed in to npm with the CTO account:
16
-
17
- - open `https://www.npmjs.com/`
18
- - click the profile menu in the top-right
19
- - click `Add an Organization`
20
- - enter the organization name `nabeh`
21
-
22
- The npm scope will be `@nabeh`.
23
-
24
- ### 3. Log in on the publish machine
25
-
26
- Use the CTO account in the terminal:
27
-
28
- ```bash
29
- npm logout
30
- npm login
31
- npm whoami
32
- ```
33
-
34
- ### 4. Build and verify the package
35
-
36
- ```bash
37
- npm run clean
38
- npm run check
39
- npm run build
40
- npm pack --dry-run
41
- ```
42
-
43
- ### 5. Publish the package publicly
44
-
45
- ```bash
46
- npm publish
47
- ```
48
-
49
- For the next release:
50
-
51
- ```bash
52
- npm version patch
53
- npm publish
54
- ```
55
-
56
- Use `patch` for fixes, `minor` for new backward-compatible features, and `major` for breaking changes.
57
-
58
- Notes:
59
-
60
- - this package uses `"publishConfig": { "access": "public" }`
61
- - public org-scoped packages still use the scoped package name
62
- - npm docs for this flow:
63
- - https://docs.npmjs.com/creating-an-organization
64
- - https://docs.npmjs.com/creating-and-publishing-an-organization-scoped-package/
65
-
66
- ## Project layout
67
-
68
- - `src/` - production TypeScript source
69
- - `docs/implementation-plan.md` - architecture and rollout notes
70
- - `local-test/mock-ai-server.js` - local mock backend
71
- - `local-test/chat-widget.js` - original quick prototype
72
- - `local-test/angular-usage-example.ts` - Angular init example
73
-
74
- ## Library API
75
-
76
- Package usage:
77
-
78
- ```ts
79
- import { createChatWidget } from "@nabeh/chat-widget";
80
-
81
- const widget = createChatWidget({
82
- apiBaseUrl: "https://api.example.com",
83
- endpoints: {
84
- ask: "/knowledge_rag/ask",
85
- history: "/knowledge_rag/get_chat_history",
86
- deleteChat: "/knowledge_rag/delete_chat",
87
- deleteLastQa: "/knowledge_rag/delete_last_qa_pair"
88
- },
89
- rag: {
90
- chatId: "customer-portal-session-123",
91
- knowledgeNames: ["employee-handbook", "policies"],
92
- enableReferences: true
93
- },
94
- getAccessToken: async () => authService.getAccessToken(),
95
- getUserContext: async () => ({
96
- userId: currentUser.id,
97
- displayName: currentUser.name
98
- })
99
- });
100
- ```
101
-
102
- Browser-global usage after loading the browser bundle:
103
-
104
- ```html
105
- <script src="https://your-cdn.example.com/browser.iife.js"></script>
106
- <script>
107
- window.ChatWidget.init({
108
- apiBaseUrl: "https://api.example.com",
109
- endpoints: {
110
- ask: "/knowledge_rag/ask",
111
- history: "/knowledge_rag/get_chat_history"
112
- },
113
- rag: {
114
- chatId: "external-client-user-42",
115
- knowledgeNames: ["client-kb-public", "client-kb-private"]
116
- },
117
- getAccessToken: async function () {
118
- return window.appAccessToken;
119
- },
120
- getUserContext: async function () {
121
- return {
122
- userId: window.currentUser?.id,
123
- displayName: window.currentUser?.name
124
- };
125
- }
126
- });
127
- </script>
128
- ```
129
-
130
- The browser bundle exposes:
131
-
132
- - `window.ChatWidget.init(config)`
133
- - `window.ChatWidget.createChatWidget(config)`
134
-
135
- `init()` returns a widget instance with methods like `open()`, `close()`, `toggle()`, `destroy()`, `loadChats()`, and `loadHistory()`.
136
-
137
- ## Angular integration
138
-
139
- There are two supported ways to use this widget in Angular:
140
-
141
- 1. load the browser bundle and call `window.ChatWidget.init(...)`
142
- 2. install the npm package and import `createChatWidget(...)`
143
-
144
- ### Option 1: Script-based Angular integration
145
-
146
- This is the closest match to your current setup.
147
-
148
- #### 1. Install or host the built bundle
149
-
150
- After `npm run build`, use:
151
-
152
- - `dist/browser.iife.js`
153
-
154
- Copy it into your Angular app assets folder, for example:
155
-
156
- - `src/assets/chat-widget/browser.iife.js`
157
-
158
- #### 2. Add the script in Angular
159
-
160
- In `angular.json`, add the built file under `architect > build > options > scripts`:
161
-
162
- ```json
163
- [
164
- "src/assets/chat-widget/browser.iife.js"
165
- ]
166
- ```
167
-
168
- Or add it directly in `src/index.html`:
169
-
170
- ```html
171
- <script src="assets/chat-widget/browser.iife.js"></script>
172
- ```
173
-
174
- #### 3. Initialize it after login
175
-
176
- Call it from a component or auth-ready service after the user session is available:
177
-
178
- ```ts
179
- declare global {
180
- interface Window {
181
- ChatWidget?: {
182
- init: (config: any) => any;
183
- };
184
- }
185
- }
186
-
187
- window.ChatWidget?.init({
188
- apiBaseUrl: "http://192.168.0.126:8788",
189
- endpoints: {
190
- ask: "/my-chats/:chatId/messages",
191
- history: "/my-chats/:chatId/messages",
192
- listChats: "/my-chats",
193
- createChat: "/my-chats",
194
- updateChat: "/my-chats/:chatId",
195
- deleteChat: "/my-chats/:chatId"
196
- },
197
- rag: {
198
- knowledgeNames: ["sample-kb"],
199
- loadHistoryOnOpen: true
200
- },
201
- getUserContext: async () => ({
202
- userId: "demo-user-8",
203
- email: "demo@example.com"
204
- })
205
- });
206
- ```
207
-
208
- Important:
209
-
210
- - `apiBaseUrl` must be your backend base URL, not the Angular frontend URL
211
- - if your backend runs on port `8788`, use `http://192.168.0.126:8788`
212
- - if authentication is required, also pass `getAccessToken`
213
-
214
- Example with token:
215
-
216
- ```ts
217
- window.ChatWidget?.init({
218
- apiBaseUrl: "http://192.168.0.126:8788",
219
- endpoints: {
220
- ask: "/my-chats/:chatId/messages",
221
- history: "/my-chats/:chatId/messages",
222
- listChats: "/my-chats",
223
- createChat: "/my-chats",
224
- updateChat: "/my-chats/:chatId",
225
- deleteChat: "/my-chats/:chatId"
226
- },
227
- rag: {
228
- knowledgeNames: ["sample-kb"],
229
- loadHistoryOnOpen: true
230
- },
231
- getAccessToken: async () => localStorage.getItem("access_token"),
232
- getUserContext: async () => ({
233
- userId: "demo-user-8",
234
- email: "demo@example.com"
235
- })
236
- });
237
- ```
238
-
239
- ### Option 2: Install from npm in Angular
240
-
241
- Install the package:
5
+ ## Installation
242
6
 
243
7
  ```bash
244
8
  npm install @nabeh/chat-widget
245
9
  ```
246
10
 
247
- Then use it in Angular:
11
+ ## Angular Usage
12
+
13
+ Use the widget after the user session is available so you can pass user context and, if needed, an access token.
248
14
 
249
15
  ```ts
250
- import { AfterViewInit, Component, OnDestroy } from "@angular/core";
251
- import { createChatWidget } from "@nabeh/chat-widget";
16
+ import { AfterViewInit, Component, OnDestroy } from '@angular/core';
17
+ import { createChatWidget } from '@nabeh/chat-widget';
252
18
 
253
19
  @Component({
254
- selector: "app-root",
255
- template: ""
20
+ selector: 'app-root',
21
+ template: ''
256
22
  })
257
23
  export class AppComponent implements AfterViewInit, OnDestroy {
258
24
  private widget?: ReturnType<typeof createChatWidget>;
259
25
 
260
26
  ngAfterViewInit(): void {
261
27
  this.widget = createChatWidget({
262
- apiBaseUrl: "http://192.168.0.126:8788",
28
+ apiBaseUrl: 'http://your-api-url',
263
29
  endpoints: {
264
- ask: "/my-chats/:chatId/messages",
265
- history: "/my-chats/:chatId/messages",
266
- listChats: "/my-chats",
267
- createChat: "/my-chats",
268
- updateChat: "/my-chats/:chatId",
269
- deleteChat: "/my-chats/:chatId"
30
+ ask: '/my-chats/:chatId/messages',
31
+ history: '/my-chats/:chatId/messages',
32
+ listChats: '/my-chats',
33
+ createChat: '/my-chats',
34
+ updateChat: '/my-chats/:chatId',
35
+ deleteChat: '/my-chats/:chatId'
270
36
  },
271
37
  rag: {
272
- knowledgeNames: ["sample-kb"],
38
+ knowledgeNames: ['sample-kb'],
273
39
  loadHistoryOnOpen: true
274
40
  },
275
41
  getUserContext: async () => ({
276
- userId: "demo-user-8",
277
- email: "demo@example.com"
42
+ userId: 'your-user-id',
43
+ // email: 'user@example.com'
278
44
  })
279
45
  });
280
46
  }
@@ -285,168 +51,70 @@ export class AppComponent implements AfterViewInit, OnDestroy {
285
51
  }
286
52
  ```
287
53
 
288
- ## Configuration reference
289
-
290
- These are the main fields you should pass from Angular:
54
+ ## Configuration
291
55
 
292
- - `apiBaseUrl`: backend base URL, for example `http://192.168.0.126:8788`
293
- - `endpoints.ask`: send-message endpoint
294
- - `endpoints.history`: fetch-history endpoint
295
- - `endpoints.listChats`: list sidebar chats
296
- - `endpoints.createChat`: create a new chat
297
- - `endpoints.updateChat`: update chat metadata like pin state
298
- - `endpoints.deleteChat`: delete a chat
299
- - `rag.knowledgeNames`: knowledge bases to query
300
- - `rag.loadHistoryOnOpen`: whether to load chat history automatically when opened
301
- - `getAccessToken`: function returning bearer token
302
- - `getUserContext`: function returning user identity information
56
+ - `apiBaseUrl`: Backend base URL. Example: `https://api.example.com`
57
+ - `endpoints.ask`: Send-message endpoint
58
+ - `endpoints.history`: Fetch chat history endpoint
59
+ - `endpoints.listChats`: List chats endpoint
60
+ - `endpoints.createChat`: Create chat endpoint
61
+ - `endpoints.updateChat`: Update chat metadata endpoint
62
+ - `endpoints.deleteChat`: Delete chat endpoint
63
+ - `rag.knowledgeNames`: Knowledge bases to query
64
+ - `rag.loadHistoryOnOpen`: Load history automatically when the widget opens
65
+ - `getUserContext`: Function that returns the current user context
66
+ - `getAccessToken`: Optional function that returns a bearer token
303
67
 
304
- Example user context:
68
+ ## Example With Token
305
69
 
306
70
  ```ts
307
- getUserContext: async () => ({
308
- userId: "demo-user-8",
309
- displayName: "Demo User",
310
- email: "demo@example.com",
311
- roles: ["researcher"]
312
- })
313
- ```
314
-
315
- ## Recommended Angular timing
316
-
317
- Initialize the widget:
318
-
319
- - after the user logs in
320
- - after token/user information is available
321
- - once per page/app shell, not on every route change
71
+ import { createChatWidget } from '@nabeh/chat-widget';
322
72
 
323
- Destroy the widget when the hosting Angular component is destroyed if you are using the npm import approach.
324
-
325
- ## Knowledge RAG integration
326
-
327
- The widget is now aligned to the `knowledge_rag` endpoints:
328
-
329
- - `POST /knowledge_rag/ask`
330
- - `GET /knowledge_rag/get_chat_history`
331
-
332
- Production guidance:
333
-
334
- - pass the bearer token with `getAccessToken()`
335
- - do not hardcode tokens into the shipped widget
336
- - use a stable `rag.chatId` per user/session if you want conversation continuity
337
- - provide `rag.knowledgeNames` from the host application, not from the widget bundle
338
- - version your hosted script URL, for example:
339
- - `/chat-widget/v1.0.0/browser.iife.js`
340
- - `/chat-widget/latest/browser.iife.js`
341
-
342
- ## Backend adapter integration
343
-
344
- When using the Postgres-backed adapter added in `backend/`, point the widget to the adapter endpoints instead of the raw RAG endpoints:
345
-
346
- ```ts
347
- createChatWidget({
348
- apiBaseUrl: "http://localhost:8788",
349
- endpoints: {
350
- ask: "/my-chats/:chatId/messages",
351
- history: "/my-chats/:chatId/messages",
352
- listChats: "/my-chats",
353
- createChat: "/my-chats",
354
- updateChat: "/my-chats/:chatId"
355
- },
356
- rag: {
357
- knowledgeNames: ["sample-kb"],
358
- loadHistoryOnOpen: false
359
- },
360
- getAccessToken: async () => authService.getAccessToken(),
361
- getUserContext: async () => ({
362
- userId: "demo-user-1",
363
- displayName: "Demo User",
364
- email: "demo@example.com",
365
- roles: ["researcher"]
366
- })
367
- });
368
- ```
369
-
370
- The widget forwards `getUserContext()` to the adapter in the `X-Chat-User-Context` header. In your dummy site you can hardcode that object for testing; in the real client integration they should populate it from their logged-in user/session data.
371
-
372
- In the hybrid adapter flow, Postgres stores chat sidebar metadata only. Full message history and chat deletion are proxied to the AI backend.
373
-
374
- ## Build outputs
375
-
376
- The library is configured to build:
377
-
378
- - `esm` for app imports
379
- - `cjs` for Node/CommonJS consumers
380
- - `iife` for script injection into an already deployed website
381
-
382
- Build tooling:
383
-
384
- ```bash
385
- npm install
386
- npm run build
387
- ```
388
-
389
- Output will be generated in `dist/`.
390
-
391
- ## Local test flow
392
-
393
- ### 1. Start the mock backend
394
-
395
- ```bash
396
- node local-test/mock-ai-server.js
397
- ```
398
-
399
- ### 2. Build the browser bundle
400
-
401
- ```bash
402
- npm install
403
- npm run build
404
- ```
405
-
406
- ### 3. Inject the built script into an Angular dummy app
407
-
408
- Copy the built browser file from `dist/` into Angular `src/assets/`, then add:
409
-
410
- ```html
411
- <script src="/assets/browser.iife.js"></script>
412
- ```
413
-
414
- ### 4. Initialize after authentication
415
-
416
- ```ts
417
- window.ChatWidget?.init({
418
- apiBaseUrl: "http://localhost:8787",
73
+ const widget = createChatWidget({
74
+ apiBaseUrl: 'http://your-api-url',
419
75
  endpoints: {
420
- ask: "/knowledge_rag/ask",
421
- history: "/knowledge_rag/get_chat_history"
76
+ ask: '/my-chats/:chatId/messages',
77
+ history: '/my-chats/:chatId/messages',
78
+ listChats: '/my-chats',
79
+ createChat: '/my-chats',
80
+ updateChat: '/my-chats/:chatId',
81
+ deleteChat: '/my-chats/:chatId'
422
82
  },
423
83
  rag: {
424
- chatId: "angular-local-test-user-123",
425
- knowledgeNames: ["sample-kb"]
84
+ knowledgeNames: ['sample-kb'],
85
+ loadHistoryOnOpen: true
426
86
  },
427
- getAccessToken: async () => "dummy-sso-token",
87
+ getAccessToken: async () => localStorage.getItem('access_token'),
428
88
  getUserContext: async () => ({
429
- userId: "u-1001",
430
- displayName: "Angular Test User"
89
+ userId: 'your-user-id',
90
+ email: 'user@example.com'
431
91
  })
432
92
  });
433
93
  ```
434
94
 
435
- ## Production integration guidance
95
+ ## Browser Global
436
96
 
437
- For the live Angular site:
97
+ If you are loading the browser bundle manually, the package also exposes:
438
98
 
439
- - host the built `iife` bundle on your CDN or app server
440
- - load it only after the user is authenticated
441
- - pass access token and user context from the host Angular app
442
- - keep RBAC validation in the AI backend
99
+ - `window.ChatWidget.init(config)`
100
+ - `window.ChatWidget.createChatWidget(config)`
443
101
 
444
- Do not embed a separate login flow inside the widget.
102
+ ## Widget Instance API
445
103
 
446
- ## Chat persistence adapter
104
+ `createChatWidget(...)` returns an instance with:
447
105
 
448
- This repo now also includes a starter backend adapter in `backend/` for storing chat metadata in Postgres and wrapping the existing RAG APIs.
106
+ - `open()`
107
+ - `close()`
108
+ - `toggle()`
109
+ - `destroy()`
110
+ - `sendMessage(message)`
111
+ - `setAccessTokenProvider(provider)`
112
+ - `getChatId()`
113
+ - `loadChats()`
114
+ - `loadHistory()`
449
115
 
450
- Setup guide:
116
+ ## Notes
451
117
 
452
- - [docs/chat-backend-setup.md](/home/tarun/learnings/knowledge-platform-cb/docs/chat-backend-setup.md)
118
+ - `apiBaseUrl` should point to your backend, not your Angular frontend
119
+ - initialize the widget after authentication if your backend requires user identity or tokens
120
+ - call `destroy()` when the hosting Angular component is destroyed