{"_id":"@clankersupport/widget-rsc","_rev":"5-ba9abdca7ec267ed08dc3efc82cf73bb","name":"@clankersupport/widget-rsc","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@clankersupport/widget-rsc","version":"1.0.0","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"license":"MIT","_id":"@clankersupport/widget-rsc@1.0.0","maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"homepage":"https://clankersupport.com","bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"dist":{"shasum":"a7b13a620a145b6e4c578700dd2bc865677bd47f","tarball":"https://registry.npmjs.org/@clankersupport/widget-rsc/-/widget-rsc-1.0.0.tgz","fileCount":48,"integrity":"sha512-5FyG8xGk1ATpMWv81Ciy3ZZM38HMxo3XdjXNLx2JHJFmMstpUvUC2MIB3lcfC+RBm427+2+dRDWcXZaQ97mZ5g==","signatures":[{"sig":"MEUCIHzjPthLPYU/l/hdpQZQInIYHyLuAgVdrvlTyVDrZ4odAiEA1FyERjk6FbcC+NRsQuQAr3OHNpT0L7n5iCy7JpId054=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143458},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./headless":{"types":"./dist/headless.d.ts","default":"./dist/headless.js"}},"gitHead":"76bace74bad340af0f23eff35001c06aa72524f7","scripts":{"lint":"prettier --check .","test":"vitest run","build":"tsc -p tsconfig.build.json","format":"prettier --write ."},"_npmUser":{"name":"steebchen","email":"contact@luca-steeb.com"},"repository":{"url":"git+https://github.com/theopenco/llmchat.git","type":"git","directory":"packages/widget-rsc"},"_npmVersion":"11.3.0","description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","directories":{},"sideEffects":false,"_nodeVersion":"24.2.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"^19.0.0","vitest":"^3.0.0","react-dom":"^19.0.0","typescript":"5.9.2","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@vitejs/plugin-react":"^4.3.0","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/widget-rsc_1.0.0_1783018997895_0.7145316332186635","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@clankersupport/widget-rsc","version":"1.0.1","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"license":"MIT","_id":"@clankersupport/widget-rsc@1.0.1","maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"homepage":"https://clankersupport.com","bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"dist":{"shasum":"97a2521a0d9b59cfd4aff06e1081425d0fadbe34","tarball":"https://registry.npmjs.org/@clankersupport/widget-rsc/-/widget-rsc-1.0.1.tgz","fileCount":48,"integrity":"sha512-3NJ2+qe1cReqcn+Ia+11WhB9yEbMH6JrdJoIG/hYR6xr+VT6MJOpWbZNZaTpkAkkykafgH+kKDPfh5Hq5jYHqw==","signatures":[{"sig":"MEUCIQDa+3YYei3U6m6stnXcppRt2B9LrAQLkRhj9q6vmaPyIwIgaMr222+PdvBAnZRhqokiCoKFqXxyrBy9UsV9J8f8GmE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@clankersupport%2fwidget-rsc@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":146971},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./headless":{"types":"./dist/headless.d.ts","default":"./dist/headless.js"}},"gitHead":"567114d9a7d3de965b2680ec85eb7c2062ac79db","scripts":{"lint":"prettier --check .","test":"vitest run","build":"tsc -p tsconfig.build.json","format":"prettier --write ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:faac41f3-032d-4446-ac27-6b56af43bd70"}},"repository":{"url":"git+https://github.com/theopenco/llmchat.git","type":"git","directory":"packages/widget-rsc"},"_npmVersion":"11.16.0","description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"^19.0.0","vitest":"^3.0.0","react-dom":"^19.0.0","typescript":"5.9.2","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@vitejs/plugin-react":"^4.3.0","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/widget-rsc_1.0.1_1783020836082_0.794026179948699","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@clankersupport/widget-rsc","version":"1.1.0","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"license":"MIT","_id":"@clankersupport/widget-rsc@1.1.0","maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"homepage":"https://clankersupport.com","bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"dist":{"shasum":"abf542ba91d3dcdd68b506eb3605ea2f3ea8861d","tarball":"https://registry.npmjs.org/@clankersupport/widget-rsc/-/widget-rsc-1.1.0.tgz","fileCount":48,"integrity":"sha512-mxt7D3GXL2q1OXr1KqU4CmJKs6hX31H0qXJ1vvxrdbNpHuxlOoB/cx4oZfx9pj9JHv2bh93PnBMxVMf+JXSPZA==","signatures":[{"sig":"MEYCIQDz/cF5dGiZ6Vk0FlrLy21kuSrsQEMDWcHUia/yARWaLAIhAJOMCvV9ef8UCwX8NiE+VRgn7QpdkxCUmfpE6WzcSZlW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@clankersupport%2fwidget-rsc@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":167364},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./headless":{"types":"./dist/headless.d.ts","default":"./dist/headless.js"}},"gitHead":"ddb2f3f8c8e63226e520f3054c100f6109200de5","scripts":{"lint":"prettier --check .","test":"vitest run","build":"tsc -p tsconfig.build.json","format":"prettier --write ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:faac41f3-032d-4446-ac27-6b56af43bd70"}},"repository":{"url":"git+https://github.com/theopenco/llmchat.git","type":"git","directory":"packages/widget-rsc"},"_npmVersion":"11.16.0","description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"^19.0.0","vitest":"^3.0.0","react-dom":"^19.0.0","typescript":"5.9.2","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@vitejs/plugin-react":"^4.3.0","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/widget-rsc_1.1.0_1783900526273_0.2214780214760379","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@clankersupport/widget-rsc","version":"1.1.1","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"license":"MIT","_id":"@clankersupport/widget-rsc@1.1.1","maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"homepage":"https://clankersupport.com","bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"dist":{"shasum":"8991e0d374f66e20b6b444e15772d29b01d83be6","tarball":"https://registry.npmjs.org/@clankersupport/widget-rsc/-/widget-rsc-1.1.1.tgz","fileCount":48,"integrity":"sha512-MB5Ah0XlTk6ClItX5S8lLgJN1Xuymdg7iAGEdwqPO0+VHkTlcqCehGB5zVCBlaM13Nu9CXlAo96xLws8BBSV6w==","signatures":[{"sig":"MEYCIQClqNLBf7pInVVUXG67dfu5zhHFdoNLDWLyWjIjWh2KUQIhANCyMCbsjPaAk86/FgBRBBI46t3KDXurDcdcZ1995bGq","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@clankersupport%2fwidget-rsc@1.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":167573},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./headless":{"types":"./dist/headless.d.ts","default":"./dist/headless.js"}},"gitHead":"3c47a9eff9aca5ba7c418a5d7040e06b1b39aa86","scripts":{"lint":"prettier --check .","test":"vitest run","build":"tsc -p tsconfig.build.json","format":"prettier --write ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:faac41f3-032d-4446-ac27-6b56af43bd70"}},"repository":{"url":"git+https://github.com/theopenco/llmchat.git","type":"git","directory":"packages/widget-rsc"},"_npmVersion":"11.16.0","description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^26.0.0","react":"^19.0.0","vitest":"^3.0.0","react-dom":"^19.0.0","typescript":"5.9.2","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@vitejs/plugin-react":"^4.3.0","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.0","@testing-library/user-event":"^14.5.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/widget-rsc_1.1.1_1784549356770_0.950851489106364","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@clankersupport/widget-rsc","version":"1.2.0","description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"homepage":"https://clankersupport.com","repository":{"type":"git","url":"git+https://github.com/theopenco/llmchat.git","directory":"packages/widget-rsc"},"license":"MIT","type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./headless":{"types":"./dist/headless.d.ts","default":"./dist/headless.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"tsc -p tsconfig.build.json","format":"prettier --write .","lint":"prettier --check .","test":"vitest run"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"devDependencies":{"@testing-library/jest-dom":"^6.6.0","@testing-library/react":"^16.1.0","@testing-library/user-event":"^14.5.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@vitejs/plugin-react":"^4.3.0","jsdom":"^26.0.0","react":"^19.0.0","react-dom":"^19.0.0","typescript":"5.9.2","vitest":"^3.0.0"},"gitHead":"45936b3f24dd7bc15d5a66f313450ea9cc4447ff","_id":"@clankersupport/widget-rsc@1.2.0","bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-SdzId9oBWaoMN1RVsKL5Jp6qqZ/yPyCrHq2D3Ydd99bhgo0vKPHtPnHS0eAbutjaUc1tMX9PnjCuyoKZkcJ+yQ==","shasum":"c8d133c2f6db72da6d9465dbca12243e5504eb73","tarball":"https://registry.npmjs.org/@clankersupport/widget-rsc/-/widget-rsc-1.2.0.tgz","fileCount":51,"unpackedSize":198371,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@clankersupport%2fwidget-rsc@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDi4d+GnifnQu4uh0+WDRmNgTgRulhK5Xp78spNvR/kzAiBLWoWA3w/OD/wUZIcjY5ZQyycD3uHGWb+NLkzWKJmVYQ=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:faac41f3-032d-4446-ac27-6b56af43bd70"}},"directories":{},"maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/widget-rsc_1.2.0_1786320788290_0.13343991804319222"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-02T19:03:17.663Z","modified":"2026-08-10T00:13:08.808Z","1.0.0":"2026-07-02T19:03:18.043Z","1.0.1":"2026-07-02T19:33:56.285Z","1.1.0":"2026-07-12T23:55:26.400Z","1.1.1":"2026-07-20T12:09:16.900Z","1.2.0":"2026-08-10T00:13:08.453Z"},"bugs":{"url":"https://github.com/theopenco/llmchat/issues"},"license":"MIT","homepage":"https://clankersupport.com","keywords":["ai","customer-support","chat-widget","react","rsc","react-server-components","nextjs","headless"],"repository":{"type":"git","url":"git+https://github.com/theopenco/llmchat.git","directory":"packages/widget-rsc"},"description":"Embed the Clanker Support AI chat widget in a React Server Components app — one component in your Next.js root layout, with headless primitives and hooks when you want to bring your own UI.","maintainers":[{"name":"steebchen","email":"contact@luca-steeb.com"}],"readme":"# @clankersupport/widget-rsc\n\nThe [Clanker Support](https://clankersupport.com) AI support widget as a **React Server Components package**. One component in your Next.js root layout puts an AI support agent on every page — and when you want your own UI, the same package gives you **headless primitives and hooks** with zero styling attached.\n\n- **RSC-first** — the entry is a Server Component that prefetches your widget config on the server (cached, revalidated every 5 min) and streams in via Suspense, so it never blocks or breaks your page.\n- **Headless underneath** — the styled widget is built entirely from exported unstyled primitives (`Trigger`, `Panel`, `Messages`, `Composer`, …) and a single `useClankerSupport()` hook. Use as much or as little as you want.\n- **Zero dependencies** — React is the only peer. The AI streaming protocol, storage, and API client are self-contained.\n- **Full feature set** — streaming AI answers, human escalation (email + Slack), operator replies appearing live via polling, per-message 👍/👎, CSAT, plan-gated branding.\n- **Open source & self-hostable** — point `apiUrl` at your own [llmchat](https://github.com/theopenco/llmchat) deployment.\n\n## Install\n\n```sh\nnpm install @clankersupport/widget-rsc\n# pnpm add / yarn add / bun add\n```\n\nRequires React 19 (Next.js 15+ App Router, or any RSC framework).\n\n## Quick start\n\nGrab your project's public key from the dashboard (Project → Embed), then add the widget to `app/layout.tsx`:\n\n```tsx\nimport { ClankerSupport } from \"@clankersupport/widget-rsc\";\n\nexport default function RootLayout({ children }) {\n\treturn (\n\t\t<html lang=\"en\">\n\t\t\t<body>\n\t\t\t\t{children}\n\t\t\t\t<ClankerSupport apiKey=\"pk_your_project_key\" />\n\t\t\t</body>\n\t\t</html>\n\t);\n}\n```\n\nThat's it. A launcher bubble appears bottom-right on every page; visitors get streaming AI answers from your knowledge base, can escalate to a human, and operator replies from the dashboard inbox show up in the widget live.\n\n> The public key is safe to expose — it's the same key the `<script>` embed uses. Keep it in an env var if you prefer: `apiKey={process.env.NEXT_PUBLIC_CLANKER_KEY!}`.\n\n### Props\n\n| Prop                  | Type                              | Default                          | What it does                                                                      |\n| --------------------- | --------------------------------- | -------------------------------- | --------------------------------------------------------------------------------- |\n| `apiKey`              | `string` (required)               | —                                | Your project's public widget key.                                                 |\n| `apiUrl`              | `string`                          | `https://api.clankersupport.com` | API origin. Point at your own deployment when self-hosting.                       |\n| `brandColor`          | `string`                          | `#111827`                        | Accent color (launcher, header, user bubbles).                                    |\n| `position`            | `\"bottom-right\" \\| \"bottom-left\"` | `\"bottom-right\"`                 | Which corner the widget docks to.                                                 |\n| `title`               | `string`                          | `\"Support\"`                      | Panel header title.                                                               |\n| `greeting`            | `string \\| null`                  | `\"Hi! How can I help?\"`          | Greeting bubble copy (personalized when the visitor identifies). `null` hides it. |\n| `escalationThreshold` | `number`                          | `3`                              | User messages before \"Talk to a human\" appears.                                   |\n| `defaultOpen`         | `boolean`                         | `false`                          | Open the panel on mount.                                                          |\n| `className`           | `string`                          | —                                | Extra class on the fixed container (handy for CSS-variable re-theming).           |\n\n### Restyling the default widget\n\nEverything is plain, namespaced CSS — `.clanker-*` classes driven by CSS custom properties. No shadow DOM, so your stylesheet wins:\n\n```css\n.clanker-root {\n\t--clanker-brand: #16a34a;\n\t--clanker-surface: #0b0f14;\n\t--clanker-text: #e5e7eb;\n\t--clanker-bubble: #1f2937;\n\t--clanker-border: #1f2937;\n}\n.clanker-panel {\n\tborder-radius: 8px;\n}\n```\n\nIf you need more than re-theming, go headless.\n\n## Headless\n\n`@clankersupport/widget-rsc/headless` exports the provider, unstyled primitives, and the hook. Primitives render semantic elements with `data-*` state attributes and forward every native prop; interactive ones support `asChild` (Radix-style) to render your own component instead.\n\n```tsx\n\"use client\";\n\nimport * as SupportChat from \"@clankersupport/widget-rsc/headless\";\n\nexport function HelpButton() {\n\treturn (\n\t\t<SupportChat.Root apiKey=\"pk_your_project_key\">\n\t\t\t<SupportChat.Trigger className=\"btn\">Need help?</SupportChat.Trigger>\n\t\t\t<SupportChat.Panel className=\"my-panel\">\n\t\t\t\t<SupportChat.Messages className=\"my-thread\">\n\t\t\t\t\t{(message) => (\n\t\t\t\t\t\t<div className={`bubble bubble--${message.role}`}>\n\t\t\t\t\t\t\t{message.content}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</SupportChat.Messages>\n\t\t\t\t<SupportChat.EscalateButton className=\"link\">\n\t\t\t\t\tTalk to a human\n\t\t\t\t</SupportChat.EscalateButton>\n\t\t\t\t<SupportChat.Composer className=\"row\">\n\t\t\t\t\t<SupportChat.Input className=\"input\" placeholder=\"Ask anything…\" />\n\t\t\t\t\t<SupportChat.Submit className=\"btn\">Send</SupportChat.Submit>\n\t\t\t\t</SupportChat.Composer>\n\t\t\t\t<SupportChat.Branding />\n\t\t\t</SupportChat.Panel>\n\t\t</SupportChat.Root>\n\t);\n}\n```\n\n### Primitives\n\n| Component        | Renders                | Notes                                                                                                     |\n| ---------------- | ---------------------- | --------------------------------------------------------------------------------------------------------- |\n| `Root`           | context only           | Alias of `ClankerSupportProvider`; accepts the same props as `ClankerSupport` (minus styling ones).       |\n| `Trigger`        | `<button>`             | Toggles the panel. `aria-expanded`, `aria-controls`, `data-state=\"open\" \\| \"closed\"`. Supports `asChild`. |\n| `Panel`          | `<div role=\"dialog\">`  | Unmounted while closed (`forceMount` keeps it for CSS animations). Focuses on open, closes on Escape.     |\n| `Messages`       | `<div role=\"log\">`     | Function child = your row markup; default rows are `<div data-part=\"message\" data-role>`. Auto-scrolls.   |\n| `Composer`       | `<form>`               | Submits the shared draft via `send()`.                                                                    |\n| `Input`          | `<input>`              | Bound to the shared draft. Typing stays enabled while a reply streams.                                    |\n| `Submit`         | `<button type=submit>` | Disabled while sending or when the draft is empty. `data-state=\"busy\" \\| \"idle\"`. Supports `asChild`.     |\n| `EscalateButton` | `<button>`             | Renders **nothing** until the visitor may escalate; hides again after. Supports `asChild`.                |\n| `ResolveButton`  | `<button>`             | Renders nothing until the conversation can be marked resolved. Supports `asChild`.                        |\n| `Branding`       | `<a>`                  | Plan-gated \"Powered by\" attribution (decided server-side). Style it freely; on free plans it must render. |\n\n### The hook\n\nSkip components entirely and drive everything yourself:\n\n```tsx\n\"use client\";\n\nimport { useClankerSupport } from \"@clankersupport/widget-rsc/headless\";\n\nfunction MyComposer() {\n\tconst { messages, status, send, escalate, canEscalate } = useClankerSupport();\n\n\treturn (\n\t\t<>\n\t\t\t{messages.map((m) => (\n\t\t\t\t<p key={m.id} data-role={m.role}>\n\t\t\t\t\t{m.content}\n\t\t\t\t</p>\n\t\t\t))}\n\t\t\t{status === \"streaming\" && <Spinner />}\n\t\t\t<button onClick={() => send(\"Where is my order?\")}>Ask</button>\n\t\t\t{canEscalate && <button onClick={escalate}>Get a human</button>}\n\t\t</>\n\t);\n}\n```\n\n`useClankerSupport()` returns (see `ClankerSupportContextValue` for the full typed surface):\n\n- **Conversation** — `messages` (merged server feed + in-flight local state), `status` (`idle | submitted | streaming | error`), `send(text?)`, `draft` / `setDraft`, `errorMessage`, `errorCode` (machine-readable API code, e.g. `subscription_required`), `conversationId`, `refresh()`.\n- **Panel** — `open`, `setOpen`, `toggle`.\n- **Identity** — `identity`, `identify({ name, email })` (persisted 30 days, per project).\n- **Handoff** — `canEscalate`, `escalate()`, `escalated`, `escalationSummary`, `canResolve`, `resolve()`, `resolved`, plus pending/failed flags.\n- **Feedback** — `rate(messageId, \"up\" | \"down\")` (optimistic with rollback), `csatEligible`, `submitCsat(1–5)`.\n- **Config** — `showBranding`, `privacyPolicyUrl`, `brandColor`, `position`, `greeting`.\n\n## How it works\n\n- **Server-side config prefetch.** `ClankerSupport` is an async Server Component: it fetches `GET /v1/config/:key` on the server (Next.js Data Cache, `revalidate: 300`) and passes the result to the client — one less client round-trip, no branding flash. The fetch is wrapped in `<Suspense fallback={null}>` and fails soft, so a slow or down API never blocks or breaks your page.\n- **Streaming.** `send()` POSTs the conversation to `/v1/chat` and reads the AI SDK UI-message stream directly (a ~90-line SSE reader — no `ai` dependency), updating the assistant bubble per delta.\n- **Live operator replies.** While the panel is open, the persisted conversation feed is polled every 2.5s and merged with local in-flight state, so replies sent from the dashboard inbox (or by email) appear without a refresh.\n- **Escalation semantics** mirror the first-party widget: escalated state hydrates from the server (a reload can't re-fire notifications), the bot stays muted while a human owns the conversation, and visitors can't resolve an escalated thread.\n- **Script-widget compatible storage.** The SDK uses the same `localStorage`/`sessionStorage` keys as the `<script>` embed, so migrating from the script tag keeps existing visitor conversations and identities.\n\n## Using it from a Client Component\n\nThe root export is a Server Component. If your layout (or the spot you're mounting from) is a Client Component, import the same widget from the headless entry instead — identical UI, config fetched client-side:\n\n```tsx\n\"use client\";\n\nimport { ClankerSupportWidget } from \"@clankersupport/widget-rsc/headless\";\n\n<ClankerSupportWidget apiKey=\"pk_your_project_key\" />;\n```\n\n## Self-hosting\n\nClanker Support is open source ([theopenco/llmchat](https://github.com/theopenco/llmchat)). Run your own API and pass its origin:\n\n```tsx\n<ClankerSupport apiKey=\"pk_…\" apiUrl=\"https://support-api.your-domain.com\" />\n```\n\n## License\n\nSee the repository license: [theopenco/llmchat](https://github.com/theopenco/llmchat).\n","readmeFilename":"README.md"}