@characterxyz/react 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Charky Labs Pvt Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,44 @@
1
- # Temporary Holding Version
1
+ # @characterxyz/react
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Your Character XYZ agent in React and Next.js: the ready-made widget as a component, and a hook for
4
+ building your own UI. Includes [`@characterxyz/widget`](https://www.npmjs.com/package/@characterxyz/widget)
5
+ and [`@characterxyz/web`](https://www.npmjs.com/package/@characterxyz/web); install only this.
6
+
7
+ ```bash
8
+ npm install @characterxyz/react
9
+ ```
10
+
11
+ ## The widget
12
+
13
+ ```tsx
14
+ import { CharacterXYZWidget } from '@characterxyz/react';
15
+
16
+ export function Support() {
17
+ return <CharacterXYZWidget publishableKey="cxyz_pk_live_…" accent="#e11d48" onReady={({ agent }) => console.log(agent.name)} />;
18
+ }
19
+ ```
20
+
21
+ It takes every widget setting as a prop (`agentId`, `display`, `position`, `mode`, `showCall`, …). Works
22
+ in the Next.js App Router as is: the package is marked `'use client'`.
23
+
24
+ ## Your own UI
25
+
26
+ ```tsx
27
+ import { useCharacterXYZ } from '@characterxyz/react';
28
+
29
+ const { messages, busy, send, startCall, call, error } = useCharacterXYZ({ publishableKey: 'cxyz_pk_live_…' });
30
+ ```
31
+
32
+ `messages` stream as the reply is written; `startCall()` must run from a click (it asks for the
33
+ microphone), and `call` carries its phase, queue position and estimate.
34
+
35
+ ## Signed-in visitors
36
+
37
+ Mint the session on your server with [`@characterxyz/server`](https://www.npmjs.com/package/@characterxyz/server)
38
+ and pass `getSessionToken={() => fetch('/api/characterxyz/session').then((r) => r.json())}` instead of a key.
39
+
40
+ Create keys and choose the sites they may run on in **Character XYZ › Settings › Developers**.
41
+
42
+ ## License
43
+
44
+ MIT
@@ -0,0 +1,41 @@
1
+ import * as react from 'react';
2
+ import { CharacterXYZ, CxError, ChatMessage, CallState, Call, InitOptions } from '@characterxyz/web';
3
+ export { Call, CallState, ChatMessage, CxError } from '@characterxyz/web';
4
+ import { MountOptions } from '@characterxyz/widget';
5
+
6
+ interface CharacterXYZWidgetProps extends MountOptions {
7
+ onReady?: (detail: {
8
+ agent: {
9
+ id: string;
10
+ name: string;
11
+ };
12
+ }) => void;
13
+ onOpen?: (view: 'chat' | 'call') => void;
14
+ onClose?: () => void;
15
+ onError?: (detail: {
16
+ code: string;
17
+ message: string;
18
+ }) => void;
19
+ }
20
+ interface CharacterXYZWidgetRef {
21
+ open(view?: 'chat' | 'call'): void;
22
+ close(): void;
23
+ }
24
+ /**
25
+ * The ready-made widget. Renders nothing in your tree: the widget lives in
26
+ * its own element at the end of <body>. Re-mounts when the key or agent changes.
27
+ */
28
+ declare const CharacterXYZWidget: react.ForwardRefExoticComponent<CharacterXYZWidgetProps & react.RefAttributes<CharacterXYZWidgetRef>>;
29
+ interface UseCharacterXYZ {
30
+ client: CharacterXYZ | null;
31
+ error: CxError | null;
32
+ messages: readonly ChatMessage[];
33
+ busy: boolean;
34
+ send(text: string): Promise<void>;
35
+ call: CallState | null;
36
+ startCall(): Promise<Call | null>;
37
+ }
38
+ /** The headless SDK as React state, for brands building their own UI. */
39
+ declare function useCharacterXYZ(options: InitOptions): UseCharacterXYZ;
40
+
41
+ export { CharacterXYZWidget, type CharacterXYZWidgetProps, type CharacterXYZWidgetRef, type UseCharacterXYZ, useCharacterXYZ };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+ import{CharacterXYZ as E}from"@characterxyz/web";import{mount as X}from"@characterxyz/widget";import{forwardRef as Y,useEffect as m,useImperativeHandle as Z,useRef as v,useState as d}from"react";var M=Y(function(r,h){let l=v(null),a=v(r);return a.current=r,Z(h,()=>({open:s=>l.current?.open(s),close:()=>l.current?.close()})),m(()=>{let{onReady:s,onOpen:p,onClose:y,onError:f,...g}=a.current,c=X(g);l.current=c;let i=c.element,n=(e,t)=>{let u=x=>t(x);return i.addEventListener(e,u),()=>i.removeEventListener(e,u)},C=[n("cx-ready",e=>a.current.onReady?.(e.detail)),n("cx-open",e=>a.current.onOpen?.(e.detail.view)),n("cx-close",()=>a.current.onClose?.()),n("cx-error",e=>a.current.onError?.(e.detail))];return()=>{C.forEach(e=>e()),c.destroy(),l.current=null}},[r.publishableKey,r.agentId,r.apiUrl]),null});function O(o){let[r,h]=d(null),[l,a]=d(null),[s,p]=d([]),[y,f]=d(!1),[g,c]=d(null),i=v(o);return i.current=o,m(()=>{let n=!1,C=null,e=[];return E.init(i.current).then(t=>{if(n)return t.destroy();C=t,h(t),e.push(t.chat.on("messages",p),t.chat.on("busy",f)),e.push(t.on("call",u=>{u&&e.push(u.on("state",c))})),t.chat.load().catch(()=>{})},t=>!n&&a(t)),()=>{n=!0,e.forEach(t=>t()),C?.destroy()}},[o.publishableKey,o.agentId,o.apiUrl]),{client:r,error:l,messages:s,busy:y,call:g,send:async n=>{await r?.chat.send(n)},startCall:async()=>r?r.startCall():null}}export{M as CharacterXYZWidget,O as useCharacterXYZ};
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.tsx"],"sourcesContent":["/**\n * `@characterxyz/react`\n *\n * ```tsx\n * import { CharacterXYZWidget } from '@characterxyz/react';\n *\n * <CharacterXYZWidget publishableKey=\"cxyz_pk_live_…\" accent=\"#e11d48\" onReady={(a) => track(a)} />\n * ```\n *\n * Or build your own UI on the headless SDK:\n *\n * ```tsx\n * const { client, messages, send, startCall, call } = useCharacterXYZ({ publishableKey });\n * ```\n */\nimport { CharacterXYZ, type Call, type CallState, type ChatMessage, type CxError, type InitOptions } from '@characterxyz/web';\nimport { mount, type MountOptions, type WidgetHandle } from '@characterxyz/widget';\nimport { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';\n\nexport interface CharacterXYZWidgetProps extends MountOptions {\n onReady?: (detail: { agent: { id: string; name: string } }) => void;\n onOpen?: (view: 'chat' | 'call') => void;\n onClose?: () => void;\n onError?: (detail: { code: string; message: string }) => void;\n}\n\nexport interface CharacterXYZWidgetRef {\n open(view?: 'chat' | 'call'): void;\n close(): void;\n}\n\n/**\n * The ready-made widget. Renders nothing in your tree: the widget lives in\n * its own element at the end of <body>. Re-mounts when the key or agent changes.\n */\nexport const CharacterXYZWidget = forwardRef<CharacterXYZWidgetRef, CharacterXYZWidgetProps>(function CharacterXYZWidget(props, ref) {\n const handle = useRef<WidgetHandle | null>(null);\n const latest = useRef(props);\n latest.current = props;\n\n useImperativeHandle(ref, () => ({\n open: (v) => handle.current?.open(v),\n close: () => handle.current?.close(),\n }));\n\n useEffect(() => {\n const { onReady, onOpen, onClose, onError, ...opts } = latest.current;\n void onReady;\n void onOpen;\n void onClose;\n void onError;\n const w = mount(opts);\n handle.current = w;\n const el = w.element;\n const on = (name: string, fn: (e: CustomEvent) => void) => {\n const h = (e: Event) => fn(e as CustomEvent);\n el.addEventListener(name, h);\n return () => el.removeEventListener(name, h);\n };\n const offs = [\n on('cx-ready', (e) => latest.current.onReady?.(e.detail)),\n on('cx-open', (e) => latest.current.onOpen?.(e.detail.view)),\n on('cx-close', () => latest.current.onClose?.()),\n on('cx-error', (e) => latest.current.onError?.(e.detail)),\n ];\n return () => {\n offs.forEach((f) => f());\n w.destroy();\n handle.current = null;\n };\n // The widget's look is read at mount; a new key or agent is a new widget.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.publishableKey, props.agentId, props.apiUrl]);\n\n return null;\n});\n\nexport interface UseCharacterXYZ {\n client: CharacterXYZ | null;\n error: CxError | null;\n messages: readonly ChatMessage[];\n busy: boolean;\n send(text: string): Promise<void>;\n call: CallState | null;\n startCall(): Promise<Call | null>;\n}\n\n/** The headless SDK as React state, for brands building their own UI. */\nexport function useCharacterXYZ(options: InitOptions): UseCharacterXYZ {\n const [client, setClient] = useState<CharacterXYZ | null>(null);\n const [error, setError] = useState<CxError | null>(null);\n const [messages, setMessages] = useState<readonly ChatMessage[]>([]);\n const [busy, setBusy] = useState(false);\n const [call, setCall] = useState<CallState | null>(null);\n const opts = useRef(options);\n opts.current = options;\n\n useEffect(() => {\n let cancelled = false;\n let c: CharacterXYZ | null = null;\n const offs: Array<() => void> = [];\n CharacterXYZ.init(opts.current).then(\n (cl) => {\n if (cancelled) return cl.destroy();\n c = cl;\n setClient(cl);\n offs.push(cl.chat.on('messages', setMessages), cl.chat.on('busy', setBusy));\n offs.push(\n cl.on('call', (k) => {\n if (k) offs.push(k.on('state', setCall));\n }),\n );\n void cl.chat.load().catch(() => {});\n },\n (e) => !cancelled && setError(e),\n );\n return () => {\n cancelled = true;\n offs.forEach((f) => f());\n c?.destroy();\n };\n }, [options.publishableKey, options.agentId, options.apiUrl]);\n\n return {\n client,\n error,\n messages,\n busy,\n call,\n send: async (text) => {\n await client?.chat.send(text);\n },\n startCall: async () => (client ? client.startCall() : null),\n };\n}\n\nexport type { Call, CallState, ChatMessage, CxError } from '@characterxyz/web';\n"],"mappings":"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","names":["CharacterXYZ","mount","forwardRef","useEffect","useImperativeHandle","useRef","useState","CharacterXYZWidget","props","ref","handle","latest","v","onReady","onOpen","onClose","onError","opts","w","el","on","name","fn","h","e","offs","f","useCharacterXYZ","options","client","setClient","error","setError","messages","setMessages","busy","setBusy","call","setCall","cancelled","c","cl","k","text"]}
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "@characterxyz/react",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "description": "Character XYZ for React: the widget as a component, and hooks over the headless SDK.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "peerDependencies": {
24
+ "react": ">=17"
25
+ },
26
+ "dependencies": {
27
+ "@characterxyz/web": "^0.1.1",
28
+ "@characterxyz/widget": "^0.1.1"
29
+ },
30
+ "devDependencies": {
31
+ "@types/react": "^19.3.0",
32
+ "@types/react-dom": "^19.3.0",
33
+ "react": "^19.3.0",
34
+ "react-dom": "^19.3.0"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "registry": "https://registry.npmjs.org/"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/characterxyz/characterxyz-sdk.git",
43
+ "directory": "packages/react"
44
+ },
45
+ "homepage": "https://character.xyz",
46
+ "scripts": {
47
+ "build": "tsup",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit",
49
+ "test": "vitest run"
50
+ }
6
51
  }