npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

knowledge-platform-chat-widget

v0.1.0

Published

Embeddable AI chat widget for Angular and other web applications.

Downloads

20

Readme

Chat Widget Library

Production-oriented TypeScript library for embedding an AI chat assistant into an Angular website or any browser-based application.

Publish to npm

Before publishing, make sure the package name is available on npm and that you are logged in:

npm login

Build and verify the package:

npm run clean
npm run check
npm run build
npm pack --dry-run

Publish it publicly:

npm publish --access public

For the next release:

npm version patch
npm publish --access public

Use patch for fixes, minor for new backward-compatible features, and major for breaking changes.

Project layout

  • src/ - production TypeScript source
  • docs/implementation-plan.md - architecture and rollout notes
  • local-test/mock-ai-server.js - local mock backend
  • local-test/chat-widget.js - original quick prototype
  • local-test/angular-usage-example.ts - Angular init example

Library API

Package usage:

import { createChatWidget } from "@knowledge-platform/chat-widget";

const widget = createChatWidget({
  apiBaseUrl: "https://api.example.com",
  endpoints: {
    ask: "/knowledge_rag/ask",
    history: "/knowledge_rag/get_chat_history",
    deleteChat: "/knowledge_rag/delete_chat",
    deleteLastQa: "/knowledge_rag/delete_last_qa_pair"
  },
  rag: {
    chatId: "customer-portal-session-123",
    knowledgeNames: ["employee-handbook", "policies"],
    enableReferences: true
  },
  getAccessToken: async () => authService.getAccessToken(),
  getUserContext: async () => ({
    userId: currentUser.id,
    displayName: currentUser.name
  })
});

Browser-global usage after loading the browser bundle:

<script src="https://your-cdn.example.com/browser.iife.js"></script>
<script>
  window.ChatWidget.init({
    apiBaseUrl: "https://api.example.com",
    endpoints: {
      ask: "/knowledge_rag/ask",
      history: "/knowledge_rag/get_chat_history"
    },
    rag: {
      chatId: "external-client-user-42",
      knowledgeNames: ["client-kb-public", "client-kb-private"]
    },
    getAccessToken: async function () {
      return window.appAccessToken;
    },
    getUserContext: async function () {
      return {
        userId: window.currentUser?.id,
        displayName: window.currentUser?.name
      };
    }
  });
</script>

The browser bundle exposes:

  • window.ChatWidget.init(config)
  • window.ChatWidget.createChatWidget(config)

init() returns a widget instance with methods like open(), close(), toggle(), destroy(), loadChats(), and loadHistory().

Angular integration

There are two supported ways to use this widget in Angular:

  1. load the browser bundle and call window.ChatWidget.init(...)
  2. install the npm package and import createChatWidget(...)

Option 1: Script-based Angular integration

This is the closest match to your current setup.

1. Install or host the built bundle

After npm run build, use:

  • dist/browser.iife.js

Copy it into your Angular app assets folder, for example:

  • src/assets/chat-widget/browser.iife.js

2. Add the script in Angular

In angular.json, add the built file under architect > build > options > scripts:

[
  "src/assets/chat-widget/browser.iife.js"
]

Or add it directly in src/index.html:

<script src="assets/chat-widget/browser.iife.js"></script>

3. Initialize it after login

Call it from a component or auth-ready service after the user session is available:

declare global {
  interface Window {
    ChatWidget?: {
      init: (config: any) => any;
    };
  }
}

window.ChatWidget?.init({
  apiBaseUrl: "http://192.168.0.126:8788",
  endpoints: {
    ask: "/my-chats/:chatId/messages",
    history: "/my-chats/:chatId/messages",
    listChats: "/my-chats",
    createChat: "/my-chats",
    updateChat: "/my-chats/:chatId",
    deleteChat: "/my-chats/:chatId"
  },
  rag: {
    knowledgeNames: ["sample-kb"],
    loadHistoryOnOpen: true
  },
  getUserContext: async () => ({
    userId: "demo-user-8",
    email: "[email protected]"
  })
});

Important:

  • apiBaseUrl must be your backend base URL, not the Angular frontend URL
  • if your backend runs on port 8788, use http://192.168.0.126:8788
  • if authentication is required, also pass getAccessToken

Example with token:

window.ChatWidget?.init({
  apiBaseUrl: "http://192.168.0.126:8788",
  endpoints: {
    ask: "/my-chats/:chatId/messages",
    history: "/my-chats/:chatId/messages",
    listChats: "/my-chats",
    createChat: "/my-chats",
    updateChat: "/my-chats/:chatId",
    deleteChat: "/my-chats/:chatId"
  },
  rag: {
    knowledgeNames: ["sample-kb"],
    loadHistoryOnOpen: true
  },
  getAccessToken: async () => localStorage.getItem("access_token"),
  getUserContext: async () => ({
    userId: "demo-user-8",
    email: "[email protected]"
  })
});

Option 2: Install from npm in Angular

Install the package:

npm install @knowledge-platform/chat-widget

Then use it in Angular:

import { AfterViewInit, Component, OnDestroy } from "@angular/core";
import { createChatWidget } from "@knowledge-platform/chat-widget";

@Component({
  selector: "app-root",
  template: ""
})
export class AppComponent implements AfterViewInit, OnDestroy {
  private widget?: ReturnType<typeof createChatWidget>;

  ngAfterViewInit(): void {
    this.widget = createChatWidget({
      apiBaseUrl: "http://192.168.0.126:8788",
      endpoints: {
        ask: "/my-chats/:chatId/messages",
        history: "/my-chats/:chatId/messages",
        listChats: "/my-chats",
        createChat: "/my-chats",
        updateChat: "/my-chats/:chatId",
        deleteChat: "/my-chats/:chatId"
      },
      rag: {
        knowledgeNames: ["sample-kb"],
        loadHistoryOnOpen: true
      },
      getUserContext: async () => ({
        userId: "demo-user-8",
        email: "[email protected]"
      })
    });
  }

  ngOnDestroy(): void {
    this.widget?.destroy();
  }
}

Configuration reference

These are the main fields you should pass from Angular:

  • apiBaseUrl: backend base URL, for example http://192.168.0.126:8788
  • endpoints.ask: send-message endpoint
  • endpoints.history: fetch-history endpoint
  • endpoints.listChats: list sidebar chats
  • endpoints.createChat: create a new chat
  • endpoints.updateChat: update chat metadata like pin state
  • endpoints.deleteChat: delete a chat
  • rag.knowledgeNames: knowledge bases to query
  • rag.loadHistoryOnOpen: whether to load chat history automatically when opened
  • getAccessToken: function returning bearer token
  • getUserContext: function returning user identity information

Example user context:

getUserContext: async () => ({
  userId: "demo-user-8",
  displayName: "Demo User",
  email: "[email protected]",
  roles: ["researcher"]
})

Recommended Angular timing

Initialize the widget:

  • after the user logs in
  • after token/user information is available
  • once per page/app shell, not on every route change

Destroy the widget when the hosting Angular component is destroyed if you are using the npm import approach.

Knowledge RAG integration

The widget is now aligned to the knowledge_rag endpoints:

  • POST /knowledge_rag/ask
  • GET /knowledge_rag/get_chat_history

Production guidance:

  • pass the bearer token with getAccessToken()
  • do not hardcode tokens into the shipped widget
  • use a stable rag.chatId per user/session if you want conversation continuity
  • provide rag.knowledgeNames from the host application, not from the widget bundle
  • version your hosted script URL, for example:
    • /chat-widget/v1.0.0/browser.iife.js
    • /chat-widget/latest/browser.iife.js

Backend adapter integration

When using the Postgres-backed adapter added in backend/, point the widget to the adapter endpoints instead of the raw RAG endpoints:

createChatWidget({
  apiBaseUrl: "http://localhost:8788",
  endpoints: {
    ask: "/my-chats/:chatId/messages",
    history: "/my-chats/:chatId/messages",
    listChats: "/my-chats",
    createChat: "/my-chats",
    updateChat: "/my-chats/:chatId"
  },
  rag: {
    knowledgeNames: ["sample-kb"],
    loadHistoryOnOpen: false
  },
  getAccessToken: async () => authService.getAccessToken(),
  getUserContext: async () => ({
    userId: "demo-user-1",
    displayName: "Demo User",
    email: "[email protected]",
    roles: ["researcher"]
  })
});

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.

In the hybrid adapter flow, Postgres stores chat sidebar metadata only. Full message history and chat deletion are proxied to the AI backend.

Build outputs

The library is configured to build:

  • esm for app imports
  • cjs for Node/CommonJS consumers
  • iife for script injection into an already deployed website

Build tooling:

npm install
npm run build

Output will be generated in dist/.

Local test flow

1. Start the mock backend

node local-test/mock-ai-server.js

2. Build the browser bundle

npm install
npm run build

3. Inject the built script into an Angular dummy app

Copy the built browser file from dist/ into Angular src/assets/, then add:

<script src="/assets/browser.iife.js"></script>

4. Initialize after authentication

window.ChatWidget?.init({
  apiBaseUrl: "http://localhost:8787",
  endpoints: {
    ask: "/knowledge_rag/ask",
    history: "/knowledge_rag/get_chat_history"
  },
  rag: {
    chatId: "angular-local-test-user-123",
    knowledgeNames: ["sample-kb"]
  },
  getAccessToken: async () => "dummy-sso-token",
  getUserContext: async () => ({
    userId: "u-1001",
    displayName: "Angular Test User"
  })
});

Production integration guidance

For the live Angular site:

  • host the built iife bundle on your CDN or app server
  • load it only after the user is authenticated
  • pass access token and user context from the host Angular app
  • keep RBAC validation in the AI backend

Do not embed a separate login flow inside the widget.

Chat persistence adapter

This repo now also includes a starter backend adapter in backend/ for storing chat metadata in Postgres and wrapping the existing RAG APIs.

Setup guide: