{"_id":"@bnagaraju7/chat-widget","name":"@bnagaraju7/chat-widget","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@bnagaraju7/chat-widget","version":"0.1.0","description":"GarudaVPN support chat widget — embeddable via npm (React) or a CDN <script> bundle.","license":"MIT","private":false,"type":"commonjs","main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./cdn":"./dist/cdn/garuda-chat-widget.iife.global.js","./package.json":"./package.json"},"sideEffects":false,"scripts":{"build:css":"tailwindcss -c tailwind.config.ts -i src/styles/source.css -o src/styles/widget.compiled.css --minify && node scripts/wrap-css.js","build:lib":"tsup --config tsup.lib.config.ts","build:cdn":"tsup --config tsup.cdn.config.ts","build":"npm run build:css && npm run build:lib && npm run build:cdn","dev":"npm run build:css && tsup --config tsup.lib.config.ts --watch","typecheck":"tsc --noEmit"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0"},"dependencies":{"@twilio/voice-sdk":"^2.18.3","framer-motion":"^12.41.0","lucide-react":"^1.21.0","react-markdown":"^10.1.0","remark-gfm":"^4.0.1"},"devDependencies":{"@types/node":"^20.19.43","@types/react":"^18","@types/react-dom":"^18","react":"^19.2.7","react-dom":"^19.2.7","tailwindcss":"^3.4.1","postcss":"^8","tsup":"^8.3.5","typescript":"^5"},"_id":"@bnagaraju7/chat-widget@0.1.0","gitHead":"2a603d73c62966d4d337624103fe41a83589db90","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-xhW9D/SbtdWc3kzBCB0/FQ1mDYnToNt0J5fVAsvViUX8O1pAHZHpmluahGjFTY8Mb6XmNZucfx6PC4w9iND/tw==","shasum":"e9ad39bd612f1eb908414ae810c20e4e43d34a81","tarball":"https://registry.npmjs.org/@bnagaraju7/chat-widget/-/chat-widget-0.1.0.tgz","fileCount":8,"unpackedSize":940292,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBsNutIXd372DHxDP8Dg/IeVL0b1TRCW3UIEMAK2OlIdAiEA9ADe2zA5kpx4/XaDCzx+iY1qjMmvFovPDdeZ1K+sIIA="}]},"_npmUser":{"name":"bnagaraju7","email":"nagaraju.batchu7@gmail.com"},"directories":{},"maintainers":[{"name":"bnagaraju7","email":"nagaraju.batchu7@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/chat-widget_0.1.0_1788235518385_0.26100776795715475"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-01T04:05:18.131Z","0.1.0":"2026-09-01T04:05:18.555Z","modified":"2026-09-01T04:05:18.782Z"},"maintainers":[{"name":"bnagaraju7","email":"nagaraju.batchu7@gmail.com"}],"description":"GarudaVPN support chat widget — embeddable via npm (React) or a CDN <script> bundle.","license":"MIT","readme":"# @bnagaraju7/chat-widget\n\nThe GarudaVPN support chat widget — AI chatbot, voice call + OTP, and\nbrowser speech-to-text input — packaged for reuse outside the main Next.js\napp:\n\n- as an **npm package** for other React apps\n- as a **CDN `<script>` bundle** for any third-party website\n\nEverything talks to your backend over plain REST (`apiBaseUrl`) — there is\nno Supabase or any other direct database dependency in this package.\n\n> Published under the `@bnagaraju7` npm scope. Forking this for your own org?\n> Change `name` in `package.json` to your own scope (`@your-npm-username/chat-widget`)\n> or an unscoped name (`garuda-chat-widget`) before running `npm publish`.\n\n## Scope\n\nThis package is intentionally smaller than the chat experience inside the\nmain app. It covers:\n\n- AI chatbot (text chat via `POST {apiBaseUrl}/api/v1/agents/chat`)\n- Voice call + OTP verification (via `{apiBaseUrl}/api/v1/call/*`, Twilio Voice SDK)\n- Browser speech-to-text input (Web Speech API)\n- End-of-chat resolution/rating flow (via `POST {apiBaseUrl}/api/v1/ratings/respond`)\n\nIt does **not** include session history, human-agent live handoff, or\nedited-message display — those depended on the main app's direct\nbrowser-to-Supabase access, which this package doesn't have. If you need\nthem here, your backend would need to expose REST endpoints for\nsessions/messages/agent-routing/agent-messages (with polling in place of\nSupabase Realtime).\n\n## Build\n\n```bash\ncd chat\nnpm install\nnpm run build\n```\n\nProduces:\n\n- `dist/index.mjs`, `dist/index.cjs`, `dist/index.d.ts` — the npm package\n- `dist/cdn/garuda-chat-widget.iife.global.js` — the CDN bundle (React/ReactDOM included)\n\n## Usage — CDN\n\n```html\n<script\n  src=\"https://cdn.example.com/garuda-chat-widget.iife.global.js\"\n  data-api-base-url=\"https://api.example.com\"\n  data-organisation-id=\"your-org-id\"\n  data-support-phone=\"+1 555 0100\"\n  async\n></script>\n```\n\nThe script auto-mounts using the `data-*` attributes on its own `<script>`\ntag. For full control (custom `user`, `authToken`, callbacks, or a dynamic\nSPA re-init), call `init` yourself instead of relying on auto-mount:\n\n```html\n<script src=\"https://cdn.example.com/garuda-chat-widget.iife.global.js\"></script>\n<script>\n  window.GarudaChat.init({\n    apiBaseUrl: \"https://api.example.com\",\n    organisationId: \"your-org-id\",\n    supportPhone: \"+1 555 0100\",\n  });\n</script>\n```\n\n## Usage — npm\n\n```bash\nnpm install @bnagaraju7/chat-widget\n```\n\n```tsx\nimport { GarudaChatWidget } from \"@bnagaraju7/chat-widget\";\n\n<GarudaChatWidget\n  config={{\n    apiBaseUrl: \"https://api.example.com\",\n    organisationId: \"your-org-id\",\n    supportPhone: \"+1 555 0100\",\n  }}\n/>;\n```\n\n`react` and `react-dom` are peer dependencies (`>=18`), so consumer apps\ndon't end up with a duplicate React copy. The package ships a `\"use client\"`\nbanner, so it works as-is in a React Server Components tree too (see Next.js\nbelow) — no extra client wrapper needed.\n\n## Usage — Next.js\n\nWorks with both the App Router and the Pages Router.\n\n**App Router** — the component can be imported directly into a Server\nComponent; it renders itself on the client because the bundle already\ncarries `\"use client\"`:\n\n```tsx\n// app/layout.tsx\nimport { GarudaChatWidget } from \"@bnagaraju7/chat-widget\";\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        {children}\n        <GarudaChatWidget\n          config={{\n            apiBaseUrl: process.env.NEXT_PUBLIC_CHAT_API_BASE_URL!,\n            organisationId: process.env.NEXT_PUBLIC_CHAT_ORG_ID,\n            supportPhone: \"+1 555 0100\",\n          }}\n        />\n      </body>\n    </html>\n  );\n}\n```\n\n**Pages Router** — mount it once in `_app.tsx`:\n\n```tsx\n// pages/_app.tsx\nimport type { AppProps } from \"next/app\";\nimport { GarudaChatWidget } from \"@bnagaraju7/chat-widget\";\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return (\n    <>\n      <Component {...pageProps} />\n      <GarudaChatWidget\n        config={{ apiBaseUrl: process.env.NEXT_PUBLIC_CHAT_API_BASE_URL! }}\n      />\n    </>\n  );\n}\n```\n\nUse `NEXT_PUBLIC_*` env vars for any config value needed in the browser —\nplain (non-`NEXT_PUBLIC_`) env vars aren't available client-side.\n\n## Usage — Odoo 19\n\nOdoo isn't React-based, so integrate via the **CDN `<script>` bundle**\n(self-contained, includes React) rather than the npm package.\n\nHost `dist/cdn/garuda-chat-widget.iife.global.js` somewhere Odoo can reach it\n(your own static hosting, or as a public asset in a custom module) and add\nthe `<script>` tag using one of:\n\n- **Website Builder, no custom module** — *Website ‣ Configuration ‣\n  Settings ‣ SEO* section has a \"Custom Code\" / head-and-body-script field\n  (or *Website ‣ Site ‣ Settings ‣ Tracking Codes* on some builds) — paste\n  the snippet into the \"Body\" custom code box so it loads on every page:\n\n  ```html\n  <script\n    src=\"https://your-static-host.example.com/garuda-chat-widget.iife.global.js\"\n    data-api-base-url=\"https://api.example.com\"\n    data-organisation-id=\"your-org-id\"\n    data-support-phone=\"+1 555 0100\"\n    async\n  ></script>\n  ```\n\n- **Custom module** — bundle the JS file under\n  `your_module/static/src/js/` and add it to the website's assets bundle in\n  `__manifest__.py`:\n\n  ```python\n  \"assets\": {\n      \"web.assets_frontend\": [\n          \"your_module/static/src/js/garuda-chat-widget.iife.global.js\",\n      ],\n  },\n  ```\n\n  then set the config once from a small QWeb-injected script (e.g. in a\n  `website.layout` inherited template) instead of `data-*` attributes:\n\n  ```xml\n  <xpath expr=\"//body\" position=\"inside\">\n    <script t-if=\"request.website\">\n      window.GarudaChat &amp;&amp; window.GarudaChat.init({\n        apiBaseUrl: \"https://api.example.com\",\n        organisationId: \"your-org-id\",\n      });\n    </script>\n  </xpath>\n  ```\n\nEither way, make sure the backend behind `apiBaseUrl` has CORS enabled for\nyour Odoo site's domain (see \"Backend prerequisite\" below).\n\n## Config reference\n\n| Field                       | Required | Description                                                                 |\n| ---------------------------- | -------- | ----------------------------------------------------------------------------- |\n| `apiBaseUrl`                 | yes      | Base URL of the support/chat REST API.                                        |\n| `organisationId`              | no       | Sent as the `organisation_id` header on every REST request.                   |\n| `supportPhone`               | no       | Phone number for the voice-call fallback. Omit to hide the call button.       |\n| `user`                       | no       | `{ id, fullname?, email? }` — used for the welcome message and rating submission. |\n| `authToken`                  | no       | Bearer token for REST requests. Omit for guest (unauthenticated) mode.        |\n| `onNavigateToKnowledgeBase`  | no       | Called when a user clicks a knowledge-base article result.                    |\n| `onUnauthorized`             | no       | Called on a 401 from an authenticated request.                                |\n\n## Backend prerequisite\n\nThe backend behind `apiBaseUrl` (chat, voice token, OTP, ratings endpoints)\nneeds CORS enabled for cross-origin requests from whatever domains will\nembed the widget.\n\n## Example\n\n`example/cdn-demo.html` loads the built IIFE bundle with placeholder config\nfor manual smoke-testing — see that file for how to serve it locally.\n","readmeFilename":"README.md","_rev":"1-6d2d3caa022b06ec9ebfddfc81d503cf"}