@characterxyz/web 0.0.0-stage → 0.1.0
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 +21 -0
- package/README.md +43 -2
- package/dist/index.d.ts +349 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -3
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
|
-
#
|
|
1
|
+
# @characterxyz/web
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The headless Character XYZ SDK: sessions, streamed chat, real-time voice calls and the call queue,
|
|
4
|
+
with no UI. Build your own interface on the same calls the ready-made widget uses. Framework-free,
|
|
5
|
+
zero dependencies, 7 KB gzipped.
|
|
6
|
+
|
|
7
|
+
Want the ready-made widget instead? Use [`@characterxyz/widget`](https://www.npmjs.com/package/@characterxyz/widget)
|
|
8
|
+
(any site) or [`@characterxyz/react`](https://www.npmjs.com/package/@characterxyz/react).
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @characterxyz/web
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { CharacterXYZ } from '@characterxyz/web';
|
|
16
|
+
|
|
17
|
+
const cx = await CharacterXYZ.init({ publishableKey: 'cxyz_pk_live_…' });
|
|
18
|
+
cx.chat.on('messages', render); // streams as the reply is written
|
|
19
|
+
await cx.chat.send('Hello!');
|
|
20
|
+
|
|
21
|
+
callButton.onclick = async () => { // from a click: it needs the microphone
|
|
22
|
+
const call = await cx.startCall({ autoAccept: true });
|
|
23
|
+
call.on('state', (s) => show(s.phase, s.position, s.etaSeconds));
|
|
24
|
+
call.on('caption', (c) => caption(c.role, c.text));
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When every line is busy, a call waits in a first-come queue with its place and an estimate; the
|
|
29
|
+
visitor can keep chatting meanwhile.
|
|
30
|
+
|
|
31
|
+
## Options
|
|
32
|
+
|
|
33
|
+
| Option | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `publishableKey` | `cxyz_pk_live_…`, safe in the page; works only from the key's allowed sites |
|
|
36
|
+
| `getSessionToken` | For signed-in visitors: returns a session your server minted with [`@characterxyz/server`](https://www.npmjs.com/package/@characterxyz/server) |
|
|
37
|
+
| `agentId` | Which of the key's agents. Default: the key's first |
|
|
38
|
+
| `storage` | `local` (remember the anonymous visitor, default) · `memory` · your own store |
|
|
39
|
+
|
|
40
|
+
Create keys and choose the sites they may run on in **Character XYZ › Settings › Developers**.
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/** A tiny typed event emitter. `on` returns the unsubscribe. */
|
|
2
|
+
declare class Emitter<Events extends Record<string, unknown>> {
|
|
3
|
+
private handlers;
|
|
4
|
+
on<K extends keyof Events>(event: K, fn: (payload: Events[K]) => void): () => void;
|
|
5
|
+
emit<K extends keyof Events>(event: K, payload: Events[K]): void;
|
|
6
|
+
clear(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type CxErrorCode = 'unauthorized' | 'forbidden' | 'not_found' | 'invalid' | 'rate_limited' | 'payment_required' | 'unavailable' | 'network' | 'unknown';
|
|
10
|
+
/** Every failure the SDK reports, with a message fit to show a visitor. */
|
|
11
|
+
declare class CxError extends Error {
|
|
12
|
+
readonly code: CxErrorCode;
|
|
13
|
+
readonly status: number;
|
|
14
|
+
constructor(code: CxErrorCode, message: string, status?: number);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** What the server says about the agent a session talks to. */
|
|
18
|
+
interface AgentCard {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
tagline: string;
|
|
22
|
+
locale: string | null;
|
|
23
|
+
/** A 2D cameo's settings when the agent has no video character. Opaque. */
|
|
24
|
+
cameo: unknown;
|
|
25
|
+
video: VideoCharacter | null;
|
|
26
|
+
}
|
|
27
|
+
interface VideoClip {
|
|
28
|
+
url: string | null;
|
|
29
|
+
/** VP9 WebM with alpha (Chromium, Firefox). */
|
|
30
|
+
alphaUrl: string | null;
|
|
31
|
+
/** H.264 MP4, colour | matte side by side (Safari, with a canvas unpack). */
|
|
32
|
+
packedUrl: string | null;
|
|
33
|
+
seconds: number | null;
|
|
34
|
+
}
|
|
35
|
+
interface VideoCharacter {
|
|
36
|
+
anchor: {
|
|
37
|
+
url: string | null;
|
|
38
|
+
alphaUrl: string | null;
|
|
39
|
+
} | null;
|
|
40
|
+
clips: Partial<Record<'idle' | 'talking' | 'listening' | 'entrance', VideoClip>>;
|
|
41
|
+
/** Where the face is, in the anchor still's pixels. */
|
|
42
|
+
face: {
|
|
43
|
+
eyes: {
|
|
44
|
+
left: {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
};
|
|
48
|
+
right: {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
};
|
|
52
|
+
} | null;
|
|
53
|
+
chin: {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
} | null;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** What this site may do, decided by the brand's plan. */
|
|
60
|
+
interface Features {
|
|
61
|
+
chat: boolean;
|
|
62
|
+
call: boolean;
|
|
63
|
+
maxCallMinutes: number;
|
|
64
|
+
}
|
|
65
|
+
interface SessionInfo {
|
|
66
|
+
token: string;
|
|
67
|
+
/** Unix seconds. */
|
|
68
|
+
expiresAt: number;
|
|
69
|
+
visitorId: string;
|
|
70
|
+
agent: AgentCard;
|
|
71
|
+
features: Features;
|
|
72
|
+
/** The look set in the Embed designer. Opaque to the core. */
|
|
73
|
+
appearance: Record<string, unknown>;
|
|
74
|
+
mode: 'live' | 'test';
|
|
75
|
+
}
|
|
76
|
+
interface ChatMessage {
|
|
77
|
+
id: string;
|
|
78
|
+
role: 'visitor' | 'agent';
|
|
79
|
+
text: string;
|
|
80
|
+
createdAt: string;
|
|
81
|
+
/** True while an agent reply is still being written. */
|
|
82
|
+
streaming?: boolean;
|
|
83
|
+
/** Set when a visitor's message could not be answered. */
|
|
84
|
+
failed?: boolean;
|
|
85
|
+
}
|
|
86
|
+
type CallPhase = 'idle' | 'joining' | 'queued' | 'ready' | 'connecting' | 'live' | 'ended';
|
|
87
|
+
type CallEndReason = 'hangup' | 'left' | 'missed' | 'timeout' | 'limit' | 'credits' | 'busy' | 'failed' | 'mic-denied' | 'unavailable';
|
|
88
|
+
interface CallState {
|
|
89
|
+
phase: CallPhase;
|
|
90
|
+
callId: string | null;
|
|
91
|
+
/** 1-based place in line while queued. */
|
|
92
|
+
position: number | null;
|
|
93
|
+
etaSeconds: number | null;
|
|
94
|
+
/** While ready: seconds left to join. */
|
|
95
|
+
holdSeconds: number | null;
|
|
96
|
+
/** While live: the cap, and how long it has run. */
|
|
97
|
+
maxSeconds: number | null;
|
|
98
|
+
startedAt: number | null;
|
|
99
|
+
endReason: CallEndReason | null;
|
|
100
|
+
muted: boolean;
|
|
101
|
+
/** The agent is speaking right now. */
|
|
102
|
+
speaking: boolean;
|
|
103
|
+
/** `listening` | `thinking` | `talking` | `idle`, as the server reports it. */
|
|
104
|
+
agentState: string;
|
|
105
|
+
error: string | null;
|
|
106
|
+
}
|
|
107
|
+
interface Caption {
|
|
108
|
+
id: string;
|
|
109
|
+
role: 'visitor' | 'agent';
|
|
110
|
+
text: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Where the SDK may remember this browser's anonymous visitor id. */
|
|
114
|
+
interface VisitorStore {
|
|
115
|
+
get(key: string): string | null;
|
|
116
|
+
set(key: string, value: string): void;
|
|
117
|
+
}
|
|
118
|
+
interface SessionSource {
|
|
119
|
+
apiUrl: string;
|
|
120
|
+
agentId?: string;
|
|
121
|
+
/** Browser path: a publishable key, exchanged from this page's origin. */
|
|
122
|
+
publishableKey?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Server path: your backend mints the session with a secret key (an
|
|
125
|
+
* identified visitor) and hands the token to the page. Called again when
|
|
126
|
+
* the session is about to run out.
|
|
127
|
+
*/
|
|
128
|
+
getSessionToken?: () => Promise<string | SessionInfo>;
|
|
129
|
+
store: VisitorStore;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Holds the current session, renews it before it runs out, and never runs
|
|
133
|
+
* two renewals at once.
|
|
134
|
+
*/
|
|
135
|
+
declare class SessionManager {
|
|
136
|
+
private readonly src;
|
|
137
|
+
private current;
|
|
138
|
+
private inflight;
|
|
139
|
+
constructor(src: SessionSource);
|
|
140
|
+
private visitorKey;
|
|
141
|
+
get info(): SessionInfo | null;
|
|
142
|
+
/** A token valid for at least the next minute. */
|
|
143
|
+
token(): Promise<string>;
|
|
144
|
+
refresh(): Promise<SessionInfo>;
|
|
145
|
+
private mint;
|
|
146
|
+
/** The session behind a token minted elsewhere (`getSessionToken` returned a string). */
|
|
147
|
+
private describe;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
interface CallEvents extends Record<string, unknown> {
|
|
151
|
+
state: CallState;
|
|
152
|
+
/** The visitor's words and the agent's reply, as they are recognised. */
|
|
153
|
+
caption: Caption;
|
|
154
|
+
/** A caption the server withdrew (the visitor was not finished). */
|
|
155
|
+
captionRemoved: string;
|
|
156
|
+
/** The turn is ready: accept() within `holdSeconds`. */
|
|
157
|
+
ready: {
|
|
158
|
+
holdSeconds: number;
|
|
159
|
+
};
|
|
160
|
+
/** One streamed face batch (kind-3 msgpack payload) for line `corr` — only with `face`. */
|
|
161
|
+
face: {
|
|
162
|
+
corr: string;
|
|
163
|
+
payload: Uint8Array;
|
|
164
|
+
};
|
|
165
|
+
/** A line of the agent's voice became audible, or ended (naturally or interrupted). */
|
|
166
|
+
line: {
|
|
167
|
+
corr: string;
|
|
168
|
+
event: 'audible' | 'end';
|
|
169
|
+
};
|
|
170
|
+
error: CxError;
|
|
171
|
+
}
|
|
172
|
+
interface CallOptions {
|
|
173
|
+
/** Join the moment it is this visitor's turn (default true). */
|
|
174
|
+
autoAccept?: boolean;
|
|
175
|
+
deviceId?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Ask for the agent's face streamed with the voice (Neural Lip Sync), for a
|
|
178
|
+
* UI that draws it. `emotion()` is read when the call connects: the face's
|
|
179
|
+
* mood as the face service takes it (`joy:0.3`), or null for neutral.
|
|
180
|
+
*/
|
|
181
|
+
face?: {
|
|
182
|
+
emotion?: () => string | null;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* One voice call: join the line, wait (chatting is fine meanwhile), accept,
|
|
187
|
+
* talk, hang up. A call is single-use; start another for the next one.
|
|
188
|
+
*/
|
|
189
|
+
declare class Call extends Emitter<CallEvents> {
|
|
190
|
+
private readonly apiUrl;
|
|
191
|
+
private readonly session;
|
|
192
|
+
private readonly agentId;
|
|
193
|
+
private readonly opts;
|
|
194
|
+
private s;
|
|
195
|
+
private ticket;
|
|
196
|
+
private eventsAbort;
|
|
197
|
+
private ws;
|
|
198
|
+
private mic;
|
|
199
|
+
private players;
|
|
200
|
+
private sampleRates;
|
|
201
|
+
private cancelled;
|
|
202
|
+
private speakingCorr;
|
|
203
|
+
private heartbeat;
|
|
204
|
+
private loudSince;
|
|
205
|
+
constructor(apiUrl: string, session: SessionManager, agentId: string, opts?: CallOptions);
|
|
206
|
+
get state(): CallState;
|
|
207
|
+
/** The line being voiced now, and how much of it has been heard (ms). */
|
|
208
|
+
audible(): {
|
|
209
|
+
corr: string;
|
|
210
|
+
ms: number;
|
|
211
|
+
} | null;
|
|
212
|
+
/** Loudness of the agent's voice right now, 0..1. */
|
|
213
|
+
voiceLevel(): number;
|
|
214
|
+
private set;
|
|
215
|
+
/**
|
|
216
|
+
* Call from a click: it unlocks audio, asks for the microphone, then joins
|
|
217
|
+
* the line (or goes straight through when a slot is free).
|
|
218
|
+
*/
|
|
219
|
+
start(): Promise<void>;
|
|
220
|
+
/** Follow the call's server-side state, reconnecting the stream if it drops. */
|
|
221
|
+
private follow;
|
|
222
|
+
private onServerEvent;
|
|
223
|
+
private ended;
|
|
224
|
+
/** Take the call now that it is this visitor's turn. */
|
|
225
|
+
accept(): void;
|
|
226
|
+
private sendJson;
|
|
227
|
+
private onMicFrame;
|
|
228
|
+
private onSocket;
|
|
229
|
+
/** Stop the agent mid-sentence (the visitor wants to speak). */
|
|
230
|
+
interrupt(): void;
|
|
231
|
+
setMuted(muted: boolean): void;
|
|
232
|
+
/** Leave the line, or hang up. */
|
|
233
|
+
hangUp(): Promise<void>;
|
|
234
|
+
private finish;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
interface ChatEvents extends Record<string, unknown> {
|
|
238
|
+
/** The whole list, after any change. */
|
|
239
|
+
messages: ChatMessage[];
|
|
240
|
+
/** True from send until the reply is complete. */
|
|
241
|
+
busy: boolean;
|
|
242
|
+
error: CxError;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Text chat with the agent. History lives on the server, so it follows the
|
|
246
|
+
* visitor across page loads (and, for an identified visitor, devices).
|
|
247
|
+
*/
|
|
248
|
+
declare class Chat extends Emitter<ChatEvents> {
|
|
249
|
+
private readonly apiUrl;
|
|
250
|
+
private readonly session;
|
|
251
|
+
private list;
|
|
252
|
+
private loaded;
|
|
253
|
+
private busy;
|
|
254
|
+
private abort;
|
|
255
|
+
constructor(apiUrl: string, session: SessionManager);
|
|
256
|
+
get messages(): readonly ChatMessage[];
|
|
257
|
+
get isBusy(): boolean;
|
|
258
|
+
private publish;
|
|
259
|
+
/** Load earlier messages (once; later calls return what is held). */
|
|
260
|
+
load(): Promise<readonly ChatMessage[]>;
|
|
261
|
+
/**
|
|
262
|
+
* Send a message; the reply streams into `messages` as it is written.
|
|
263
|
+
* Resolves with the finished reply.
|
|
264
|
+
*/
|
|
265
|
+
send(text: string): Promise<ChatMessage>;
|
|
266
|
+
/** Send a failed message again. */
|
|
267
|
+
retry(id: string): Promise<ChatMessage>;
|
|
268
|
+
/** Stop listening to a reply in progress (the server still finishes it). */
|
|
269
|
+
stop(): void;
|
|
270
|
+
private replace;
|
|
271
|
+
private setBusy;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
declare const DEFAULT_API_URL = "https://api.character.xyz";
|
|
275
|
+
interface InitOptions {
|
|
276
|
+
/** `cxyz_pk_live_…` — safe in the page; works only from the key's allowed sites. */
|
|
277
|
+
publishableKey?: string;
|
|
278
|
+
/**
|
|
279
|
+
* For signed-in visitors: return a session your server minted with its
|
|
280
|
+
* secret key (see `@characterxyz/server`). Called again before expiry.
|
|
281
|
+
*/
|
|
282
|
+
getSessionToken?: () => Promise<string | SessionInfo>;
|
|
283
|
+
/** Which of the key's agents to talk to. Defaults to the key's first. */
|
|
284
|
+
agentId?: string;
|
|
285
|
+
/** Override the API (staging, local development). */
|
|
286
|
+
apiUrl?: string;
|
|
287
|
+
/** Remember the anonymous visitor across visits (default) or not at all. */
|
|
288
|
+
storage?: 'local' | 'memory' | VisitorStore;
|
|
289
|
+
}
|
|
290
|
+
interface ClientEvents extends Record<string, unknown> {
|
|
291
|
+
/** A call started or ended; the widget swaps its view on this. */
|
|
292
|
+
call: Call | null;
|
|
293
|
+
error: CxError;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The headless SDK. `await CharacterXYZ.init({ publishableKey })`, then use
|
|
297
|
+
* `chat` and `startCall()`. Everything the widget does goes through here, so
|
|
298
|
+
* a brand can build its own UI on the same calls.
|
|
299
|
+
*/
|
|
300
|
+
declare class CharacterXYZ extends Emitter<ClientEvents> {
|
|
301
|
+
readonly apiUrl: string;
|
|
302
|
+
private readonly session;
|
|
303
|
+
private info;
|
|
304
|
+
readonly chat: Chat;
|
|
305
|
+
private currentCall;
|
|
306
|
+
private destroyed;
|
|
307
|
+
private constructor();
|
|
308
|
+
static init(opts: InitOptions): Promise<CharacterXYZ>;
|
|
309
|
+
get agent(): AgentCard;
|
|
310
|
+
get features(): Features;
|
|
311
|
+
get appearance(): Record<string, unknown>;
|
|
312
|
+
get visitorId(): string;
|
|
313
|
+
get mode(): 'live' | 'test';
|
|
314
|
+
/** The call in progress (queued, ready or live), if any. */
|
|
315
|
+
get call(): Call | null;
|
|
316
|
+
/**
|
|
317
|
+
* The worn video character's full render data (the public projection the
|
|
318
|
+
* app's Stage reads), for a UI that draws the face — the widget hands it to
|
|
319
|
+
* the app's renderer. Null when the agent wears none.
|
|
320
|
+
*/
|
|
321
|
+
videoAvatar(): Promise<Record<string, unknown> | null>;
|
|
322
|
+
/** Start a voice call. Call from a click: it needs the microphone and audio unlocked. */
|
|
323
|
+
startCall(opts?: CallOptions): Promise<Call>;
|
|
324
|
+
destroy(): void;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* `@characterxyz/web` — Character XYZ on any web page, headless.
|
|
329
|
+
*
|
|
330
|
+
* ```ts
|
|
331
|
+
* import { CharacterXYZ } from '@characterxyz/web';
|
|
332
|
+
*
|
|
333
|
+
* const cx = await CharacterXYZ.init({ publishableKey: 'cxyz_pk_live_…' });
|
|
334
|
+
* cx.chat.on('messages', render);
|
|
335
|
+
* await cx.chat.send('Hi!');
|
|
336
|
+
*
|
|
337
|
+
* button.onclick = async () => {
|
|
338
|
+
* const call = await cx.startCall();
|
|
339
|
+
* call.on('state', (s) => show(s.phase, s.position));
|
|
340
|
+
* };
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* The ready-made widget is `@characterxyz/widget`; this package is what it
|
|
344
|
+
* is built on, for brands who want their own UI.
|
|
345
|
+
*/
|
|
346
|
+
|
|
347
|
+
declare const VERSION = "0.1.0";
|
|
348
|
+
|
|
349
|
+
export { type AgentCard, Call, type CallEndReason, type CallEvents, type CallOptions, type CallPhase, type CallState, type Caption, CharacterXYZ, Chat, type ChatEvents, type ChatMessage, type ClientEvents, CxError, type CxErrorCode, DEFAULT_API_URL, Emitter, type Features, type InitOptions, type SessionInfo, VERSION, type VideoCharacter, type VideoClip, type VisitorStore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
var K=Object.defineProperty;var j=(r,n,e)=>n in r?K(r,n,{enumerable:true,configurable:true,writable:true,value:e}):r[n]=e;var i=(r,n,e)=>j(r,typeof n!="symbol"?n+"":n,e);var v=null;function M(){return (!v||v.state==="closed")&&(v=new AudioContext({latencyHint:"interactive"})),v.state==="suspended"&&v.resume().catch(()=>{}),v}var x=class{constructor(n={}){i(this,"opts",n);i(this,"ctx");i(this,"gain");i(this,"analyser");i(this,"data");i(this,"nextAt",0);i(this,"started",false);i(this,"ended",false);i(this,"finishing",false);i(this,"sources",new Set);i(this,"startedAt",0);i(this,"sampleRate");this.ctx=M(),this.sampleRate=n.sampleRate??16e3,this.gain=this.ctx.createGain(),this.gain.gain.value=n.volume??1,this.analyser=this.ctx.createAnalyser(),this.analyser.fftSize=512,this.data=new Uint8Array(new ArrayBuffer(this.analyser.fftSize)),this.gain.connect(this.analyser).connect(this.ctx.destination);}enqueue(n){if(this.ended||n.byteLength<2)return;let e=Math.floor(n.byteLength/2),t=new DataView(n.buffer,n.byteOffset,e*2),s=this.ctx.createBuffer(1,e,this.sampleRate),o=s.getChannelData(0);for(let h=0;h<e;h++)o[h]=t.getInt16(h*2,true)/32768;let a=this.ctx.createBufferSource();a.buffer=s,a.connect(this.gain);let c=this.ctx.currentTime;if(this.nextAt<c&&(this.nextAt=c+(this.started?.02:.12)),a.start(this.nextAt),!this.started){this.started=true;let h=Math.max(0,(this.nextAt-c)*1e3);this.startedAt=performance.now()+h,setTimeout(()=>this.opts.onStart?.(),h);}this.nextAt+=s.duration,this.sources.add(a),a.onended=()=>{this.sources.delete(a),this.finishing&&this.sources.size===0&&this.finish();};}end(){this.finishing=true,this.sources.size===0&&this.finish();}stop(){this.ended=true;for(let n of this.sources)try{n.stop();}catch{}this.sources.clear(),this.gain.disconnect();}playedMs(){return this.started?Math.max(0,performance.now()-this.startedAt):0}level(){this.analyser.getByteTimeDomainData(this.data);let n=0;for(let e=0;e<this.data.length;e++){let t=(this.data[e]-128)/128;n+=t*t;}return Math.min(1,Math.sqrt(n/this.data.length)*3)}finish(){this.ended||(this.ended=true,this.gain.disconnect(),this.opts.onEnd?.());}};var F=`
|
|
2
|
+
class CxyzMic extends AudioWorkletProcessor {
|
|
3
|
+
constructor(o) {
|
|
4
|
+
super();
|
|
5
|
+
this.ratio = sampleRate / 16000;
|
|
6
|
+
this.pos = 0;
|
|
7
|
+
this.lp = 0;
|
|
8
|
+
this.alpha = Math.min(1, 2 * Math.PI * 7000 / sampleRate / (1 + 2 * Math.PI * 7000 / sampleRate));
|
|
9
|
+
this.out = new Int16Array(480);
|
|
10
|
+
this.n = 0;
|
|
11
|
+
}
|
|
12
|
+
process(inputs) {
|
|
13
|
+
const ch = inputs[0] && inputs[0][0];
|
|
14
|
+
if (!ch) return true;
|
|
15
|
+
for (let i = 0; i < ch.length; i++) {
|
|
16
|
+
this.lp += this.alpha * (ch[i] - this.lp);
|
|
17
|
+
this.pos += 1;
|
|
18
|
+
if (this.pos >= this.ratio) {
|
|
19
|
+
this.pos -= this.ratio;
|
|
20
|
+
const s = Math.max(-1, Math.min(1, this.lp));
|
|
21
|
+
this.out[this.n++] = s < 0 ? s * 0x8000 : s * 0x7fff;
|
|
22
|
+
if (this.n === 480) {
|
|
23
|
+
this.port.postMessage(this.out.buffer, [this.out.buffer]);
|
|
24
|
+
this.out = new Int16Array(480);
|
|
25
|
+
this.n = 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
registerProcessor('cxyz-mic', CxyzMic);
|
|
33
|
+
`;function q(r){let n=new Int16Array(r);if(!n.length)return 0;let e=0;for(let t=0;t<n.length;t++){let s=n[t]/32768;e+=s*s;}return Math.sqrt(e/n.length)}async function _(r){if(!navigator.mediaDevices?.getUserMedia)throw new Error("This browser cannot use a microphone here.");let n=await navigator.mediaDevices.getUserMedia({audio:{deviceId:r.deviceId?{exact:r.deviceId}:void 0,channelCount:1,echoCancellation:true,noiseSuppression:true,autoGainControl:true}}),e=new AudioContext({latencyHint:"interactive"}),t=e.createMediaStreamSource(n),s=false,o=l=>{if(s){r.onFrame(new ArrayBuffer(l.byteLength),0);return}r.onFrame(l,q(l));},a,c;try{let l=URL.createObjectURL(new Blob([F],{type:"application/javascript"}));try{await e.audioWorklet.addModule(l);}finally{URL.revokeObjectURL(l);}let u=new AudioWorkletNode(e,"cxyz-mic");u.port.onmessage=p=>o(p.data),a=u,c=()=>{u.port.onmessage=null;};}catch{let l=e.createScriptProcessor(4096,1,1),u=e.sampleRate/16e3,p=0,m=new Int16Array(480),f=0;l.onaudioprocess=D=>{let I=D.inputBuffer.getChannelData(0);for(let A=0;A<I.length;A++)if(p+=1,p>=u){p-=u;let E=Math.max(-1,Math.min(1,I[A]));m[f++]=E<0?E*32768:E*32767,f===480&&(o(m.buffer),m=new Int16Array(480),f=0);}},a=l,c=()=>{l.onaudioprocess=null;};}t.connect(a);let h=e.createGain();return h.gain.value=0,a.connect(h).connect(e.destination),e.state==="suspended"&&await e.resume().catch(()=>{}),{get muted(){return s},setMuted(l){s=l;for(let u of n.getAudioTracks())u.enabled=!l;},stop(){c();try{t.disconnect(),a.disconnect();}catch{}for(let l of n.getTracks())l.stop();e.close().catch(()=>{});}}}var g=class{constructor(){i(this,"handlers",{});}on(n,e){var t;return ((t=this.handlers)[n]??(t[n]=new Set)).add(e),()=>this.handlers[n]?.delete(e)}emit(n,e){for(let t of this.handlers[n]??[])try{t(e);}catch(s){console.error("[characterxyz] listener threw",s);}}clear(){this.handlers={};}};var d=class extends Error{constructor(e,t,s=0){super(t);i(this,"code");i(this,"status");this.name="CxError",this.code=e,this.status=s;}};function T(r){switch(r){case 401:return "unauthorized";case 403:return "forbidden";case 404:return "not_found";case 402:return "payment_required";case 422:return "invalid";case 429:return "rate_limited";case 503:return "unavailable";default:return "unknown"}}async function z(r){let n="";try{let e=await r.json();typeof e?.message=="string"&&(n=e.message);}catch{}return new d(T(r.status),n||`Request failed (${r.status})`,r.status)}async function w(r,n,e={}){let t={};e.body!==void 0&&(t["Content-Type"]="application/json"),e.token&&(t.Authorization=`Bearer ${e.token}`);let s;try{s=await fetch(r+n,{method:e.method??(e.body===void 0?"GET":"POST"),headers:t,body:e.body===void 0?void 0:JSON.stringify(e.body),signal:e.signal,credentials:"omit",cache:"no-store"});}catch(o){throw o?.name==="AbortError"?o:new d("network","Could not reach Character XYZ. Check your connection.")}if(!s.ok)throw await z(s);return s}async function y(r,n,e={}){return (await(await w(r,n,e)).json()).data}async function k(r,n,e){let t=r.body;if(!t)return;let s=t.getReader(),o=new TextDecoder,a="",c=()=>{s.cancel().catch(()=>{});};e?.addEventListener("abort",c);try{for(;;){let{value:h,done:l}=await s.read();if(l)break;a+=o.decode(h,{stream:!0}),a=P(a,n);}a+=o.decode(),P(a+`
|
|
34
|
+
|
|
35
|
+
`,n);}finally{e?.removeEventListener("abort",c);}}function P(r,n){let t=r.replace(/\r\n/g,`
|
|
36
|
+
`),s;for(;(s=t.indexOf(`
|
|
37
|
+
|
|
38
|
+
`))!==-1;){let o=t.slice(0,s);t=t.slice(s+2);let a="message",c=[];for(let u of o.split(`
|
|
39
|
+
`)){if(!u||u.startsWith(":"))continue;let p=u.indexOf(":"),m=p===-1?u:u.slice(0,p),f=p===-1?"":u.slice(p+1).replace(/^ /,"");m==="event"?a=f:m==="data"&&c.push(f);}if(!c.length)continue;let h=c.join(`
|
|
40
|
+
`),l=h;try{l=JSON.parse(h);}catch{}n({event:a,data:l});}return t}function U(r){if(r.byteLength<25)return null;let n=new DataView(r);if(n.getUint8(0)!==67||n.getUint8(1)!==88||n.getUint8(2)!==89||n.getUint8(3)!==90||n.getUint8(4)!==1)return null;let e=n.getUint8(5),t=(n.getUint8(6)&1)!==0,s=7,o=n.getUint16(s,true);if(s+=2,s+o+20>r.byteLength)return null;let a=new TextDecoder().decode(new Uint8Array(r,s,o));s+=o+4+8+4;let c=n.getUint32(s,true);return s+=4,s+c>r.byteLength?null:{kind:e,final:t,corr:a,payload:new Uint8Array(r,s,c)}}var $=.09,V=350,J=25e3,W=()=>({phase:"idle",callId:null,position:null,etaSeconds:null,holdSeconds:null,maxSeconds:null,startedAt:null,endReason:null,muted:false,speaking:false,agentState:"idle",error:null}),b=class extends g{constructor(e,t,s,o={}){super();i(this,"apiUrl",e);i(this,"session",t);i(this,"agentId",s);i(this,"opts",o);i(this,"s",W());i(this,"ticket",null);i(this,"eventsAbort",null);i(this,"ws",null);i(this,"mic",null);i(this,"players",new Map);i(this,"sampleRates",new Map);i(this,"cancelled",new Set);i(this,"speakingCorr",null);i(this,"heartbeat",null);i(this,"loudSince",null);}get state(){return this.s}audible(){let e=this.speakingCorr,t=e?this.players.get(e):void 0;return e&&t?{corr:e,ms:t.playedMs()}:null}voiceLevel(){let e=this.speakingCorr?this.players.get(this.speakingCorr):void 0;return e?e.level():0}set(e){this.s={...this.s,...e},this.emit("state",this.s);}async start(){if(this.s.phase==="idle"){this.set({phase:"joining"}),M();try{this.mic=await _({deviceId:this.opts.deviceId,onFrame:(e,t)=>this.onMicFrame(e,t)});}catch{this.finish("mic-denied","Allow the microphone to talk, or chat instead.");return}try{let e=await this.session.token(),t=await y(this.apiUrl,"/sdk/v1/calls",{method:"POST",body:{},token:e});this.set({callId:t.callId,phase:t.state==="ready"?"joining":"queued",position:t.position??null,etaSeconds:t.etaSeconds??null}),this.follow();}catch(e){let t=e instanceof d?e:new d("unknown","Could not start the call."),s=t.code==="rate_limited"?"busy":"unavailable";this.finish(s,t.message),this.emit("error",t);}}}async follow(){let e=0;for(;this.s.callId&&this.s.phase!=="ended"&&this.s.phase!=="idle";){this.eventsAbort=new AbortController;try{let t=await this.session.token(),s=await w(this.apiUrl,`/sdk/v1/calls/${encodeURIComponent(this.s.callId)}/events`,{token:t,signal:this.eventsAbort.signal});e=0,await k(s,o=>this.onServerEvent(o.event,o.data),this.eventsAbort.signal);}catch(t){if(t?.name==="AbortError")return;if(t instanceof d&&t.code==="not_found"){this.finish("failed","The call ended.");return}if(e+=1,e>5){this.finish("failed","Lost the connection to the call.");return}}if(this.ended())return;await new Promise(t=>setTimeout(t,Math.min(4e3,500*2**e)));}}onServerEvent(e,t){switch(e){case "queued":(this.s.phase==="joining"||this.s.phase==="queued")&&this.set({phase:"queued",position:Number(t.position)||1,etaSeconds:Number(t.etaSeconds)||null});break;case "ready":{typeof t.ticket=="string"&&t.ticket&&(this.ticket=t.ticket);let s=Number(t.holdSeconds)||0;this.s.phase!=="ready"&&this.s.phase!=="connecting"&&this.s.phase!=="live"?(this.set({phase:"ready",holdSeconds:s,position:null,etaSeconds:null}),this.emit("ready",{holdSeconds:s}),this.opts.autoAccept!==false&&this.accept()):this.s.phase==="ready"&&this.set({holdSeconds:s});break}case "live":this.set({phase:"live",maxSeconds:Number(t.maxSeconds)||null,startedAt:this.s.startedAt??Date.now()-(Number(t.elapsedSeconds)||0)*1e3});break;case "ended":this.finish(String(t.reason||"hangup")||"hangup",null);break}}ended(){return this.s.phase==="ended"}accept(){if(this.s.phase!=="ready"||!this.ticket||this.ws)return;this.set({phase:"connecting"});let e=this.apiUrl.replace(/^http/,"ws")+"/sdk/v1/calls/socket",t=new WebSocket(e,[`cxyz-ticket.${this.ticket}`]);this.ticket=null,t.binaryType="arraybuffer",this.ws=t,t.onopen=()=>{let s=this.opts.face,o=s?.emotion?.()??null;t.send(JSON.stringify({type:"agent_identity",agent_id:this.agentId,skin_index:0,blendshapes:!!s,...s?{blendshape_stream:true}:{},...s&&o?{face_emotion:o}:{}})),t.send(JSON.stringify({type:"mic_state",silero:"off",denoise:false})),this.heartbeat=setInterval(()=>this.sendJson({type:"heartbeat"}),J),this.set({phase:"live",startedAt:this.s.startedAt??Date.now()});},t.onmessage=s=>this.onSocket(s.data),t.onclose=()=>{this.ws=null,setTimeout(()=>{(this.s.phase==="live"||this.s.phase==="connecting")&&this.finish("hangup",null);},1500);};}sendJson(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e));}onMicFrame(e,t){let s=this.ws;if(!(!s||s.readyState!==WebSocket.OPEN)){if(this.speakingCorr){let o=performance.now();if(t>$){if(this.loudSince??(this.loudSince=o),o-this.loudSince>=V){this.loudSince=null,this.interrupt(),s.send(e);return}}else this.loudSince=null;s.send(new ArrayBuffer(e.byteLength));return}s.send(e);}}onSocket(e){if(e instanceof ArrayBuffer){let s=U(e);if(!s||this.cancelled.has(s.corr))return;if(s.kind===3){this.opts.face&&this.emit("face",{corr:s.corr,payload:s.payload.slice()});return}if(s.kind!==1)return;let o=this.players.get(s.corr);if(!o){for(let[c,h]of this.players)h.stop(),this.players.delete(c);let a=s.corr;o=new x({sampleRate:this.sampleRates.get(a)??16e3,onStart:()=>{this.speakingCorr=a,this.set({speaking:true}),this.emit("line",{corr:a,event:"audible"}),this.sendJson({type:"playback_started",correlationId:a,timestampMs:Date.now()});},onEnd:()=>{this.players.delete(a),this.speakingCorr===a&&(this.speakingCorr=null),this.set({speaking:false}),this.emit("line",{corr:a,event:"end"}),this.sendJson({type:"playback_ended",correlationId:a,timestampMs:Date.now(),reason:"natural"}),this.sendJson({type:"speech_ended"});}}),this.players.set(a,o);}o.enqueue(s.payload),s.final&&o.end();return}if(typeof e!="string")return;let t;try{t=JSON.parse(e);}catch{return}if("AgentSpeechMeta"in t){let s=t.AgentSpeechMeta;s?.correlation_id&&s.sample_rate&&this.sampleRates.set(s.correlation_id,s.sample_rate);return}if("InteractorTranscript"in t){let s=t.InteractorTranscript;s?.text&&this.emit("caption",{id:`v:${s.correlation_id}`,role:"visitor",text:s.text});return}if("AgentReplyTranscript"in t){let s=t.AgentReplyTranscript;s?.text&&!this.cancelled.has(s.correlation_id)&&this.emit("caption",{id:`a:${s.correlation_id}`,role:"agent",text:s.text});return}if(t.type==="turn_cancelled"&&typeof t.correlationId=="string"){let s=t.correlationId;this.cancelled.add(s),this.players.get(s)?.stop(),this.players.delete(s),this.emit("line",{corr:s,event:"end"}),this.speakingCorr===s&&(this.speakingCorr=null,this.set({speaking:false})),this.emit("captionRemoved",`a:${s}`);return}t.kind==="agent_status"&&typeof t.state=="string"&&this.set({agentState:t.state.toLowerCase()});}interrupt(){let e=this.speakingCorr;if(!e)return;let t=this.players.get(e),s=Math.round(t?.playedMs()??0);t?.stop(),this.players.delete(e),this.cancelled.add(e),this.speakingCorr=null,this.set({speaking:false}),this.emit("line",{corr:e,event:"end"}),this.sendJson({type:"playback_ended",correlationId:e,timestampMs:Date.now(),reason:"interrupted"}),this.sendJson({type:"interrupt",correlationId:e,heardMs:s,timestampMs:Date.now()});}setMuted(e){this.mic?.setMuted(e),this.set({muted:e});}async hangUp(){let e=this.s.callId,t=this.s.phase;if(this.finish(t==="live"?"hangup":"left",null),!!e)try{let s=await this.session.token();await w(this.apiUrl,`/sdk/v1/calls/${encodeURIComponent(e)}`,{method:"DELETE",token:s});}catch{}}finish(e,t){if(this.s.phase==="ended")return;this.eventsAbort?.abort(),this.eventsAbort=null,this.heartbeat&&clearInterval(this.heartbeat),this.heartbeat=null;for(let o of this.players.values())o.stop();this.players.clear(),this.speakingCorr=null,this.mic?.stop(),this.mic=null;let s=this.ws;this.ws=null,s&&s.readyState<=WebSocket.OPEN&&s.close(1e3),this.ticket=null,this.set({phase:"ended",endReason:e,speaking:false,holdSeconds:null,error:t});}};var G=0,O=r=>`${r}_${Date.now().toString(36)}_${(G++).toString(36)}`,S=class extends g{constructor(e,t){super();i(this,"apiUrl",e);i(this,"session",t);i(this,"list",[]);i(this,"loaded",false);i(this,"busy",false);i(this,"abort",null);}get messages(){return this.list}get isBusy(){return this.busy}publish(){this.list=[...this.list],this.emit("messages",this.list);}async load(){if(this.loaded)return this.list;let e=await this.session.token(),t=await y(this.apiUrl,"/sdk/v1/chat/messages?limit=50",{token:e}),s=this.list;return this.list=[...t?.messages??[],...s],this.loaded=true,this.publish(),this.list}async send(e){let t=e.trim();if(!t)throw new d("invalid","Say something first.");if(this.busy)throw new d("rate_limited","Wait for the reply first.");this.setBusy(true);let s={id:O("local"),role:"visitor",text:t,createdAt:new Date().toISOString()},o={id:O("reply"),role:"agent",text:"",createdAt:new Date().toISOString(),streaming:true};this.list.push(s,o),this.publish(),this.abort=new AbortController;try{let a=await this.session.token(),c=await w(this.apiUrl,"/sdk/v1/chat/messages",{method:"POST",body:{text:t},token:a,signal:this.abort.signal}),h=null,l=null;if(await k(c,({event:p,data:m})=>{let f=m;p==="delta"&&typeof f?.text=="string"?(o.text+=f.text,this.publish()):p==="done"?h={id:String(f.id),role:"agent",text:String(f.text??o.text),createdAt:String(f.createdAt??o.createdAt)}:p==="error"&&(l=typeof f?.message=="string"?f.message:"Something went wrong.");},this.abort.signal),l||!h)throw new d("unknown",l??"The reply was cut off. Try again.");let u=h;return this.replace(o.id,u),u}catch(a){let c=a instanceof d?a:new d("network","The reply was cut off. Try again.");this.list=this.list.filter(l=>l.id!==o.id);let h=this.list.findIndex(l=>l.id===s.id);throw h!==-1&&(this.list[h]={...s,failed:true}),this.publish(),a?.name!=="AbortError"&&this.emit("error",c),c}finally{this.abort=null,this.setBusy(false);}}retry(e){let t=this.list.find(s=>s.id===e&&s.failed);if(!t)throw new d("not_found","Nothing to retry.");return this.list=this.list.filter(s=>s.id!==e),this.publish(),this.send(t.text)}stop(){this.abort?.abort();}replace(e,t){let s=this.list.findIndex(o=>o.id===e);s!==-1&&(this.list[s]=t),this.publish();}setBusy(e){this.busy=e,this.emit("busy",e);}};var L=()=>{let r=new Map;return {get:n=>r.get(n)??null,set:(n,e)=>{r.set(n,e);}}},B=()=>({get(r){try{return globalThis.localStorage?.getItem(r)??null}catch{return null}},set(r,n){try{globalThis.localStorage?.setItem(r,n);}catch{}}}),H=60,C=class{constructor(n){i(this,"src",n);i(this,"current",null);i(this,"inflight",null);if(!n.publishableKey&&!n.getSessionToken)throw new d("invalid","Pass a publishableKey, or getSessionToken for sessions your server mints.")}visitorKey(){return `cxyz:visitor:${(this.src.publishableKey??"server").slice(-12)}`}get info(){return this.current}async token(){let n=Date.now()/1e3;return this.current&&this.current.expiresAt-H>n?this.current.token:(await this.refresh()).token}refresh(){return this.inflight??(this.inflight=this.mint().finally(()=>{this.inflight=null;})),this.inflight}async mint(){let n;if(this.src.getSessionToken){let e=await this.src.getSessionToken();typeof e=="string"?n=await this.describe(e):n=e;}else {let e=this.src.store.get(this.visitorKey())??void 0;n=await y(this.src.apiUrl,"/sdk/v1/sessions",{method:"POST",body:{publishableKey:this.src.publishableKey,agentId:this.src.agentId,visitorId:e}}),this.src.store.set(this.visitorKey(),n.visitorId);}return this.current=n,n}async describe(n){return {...await y(this.src.apiUrl,"/sdk/v1/session",{token:n}),token:n}}};var N="https://api.character.xyz",R=class r extends g{constructor(e,t,s){super();i(this,"apiUrl",e);i(this,"session",t);i(this,"info",s);i(this,"chat");i(this,"currentCall",null);i(this,"destroyed",false);this.chat=new S(e,t);}static async init(e){let t=(e.apiUrl??N).replace(/\/+$/,"");if(e.publishableKey&&/^cxyz_sk_/.test(e.publishableKey))throw new d("invalid","That is a SECRET key. Never put it in a web page: use a publishable key (cxyz_pk_\u2026). Revoke the secret key now.");let s=e.storage==="memory"?L():e.storage&&typeof e.storage=="object"?e.storage:B(),o=new C({apiUrl:t,agentId:e.agentId,publishableKey:e.publishableKey,getSessionToken:e.getSessionToken,store:s}),a=await o.refresh();return new r(t,o,a)}get agent(){return (this.session.info??this.info).agent}get features(){return (this.session.info??this.info).features}get appearance(){return (this.session.info??this.info).appearance??{}}get visitorId(){return (this.session.info??this.info).visitorId}get mode(){return (this.session.info??this.info).mode}get call(){return this.currentCall&&this.currentCall.state.phase!=="ended"?this.currentCall:null}async videoAvatar(){let e=await this.session.token();return y(this.apiUrl,"/sdk/v1/agent/video-avatar",{token:e})}async startCall(e={}){if(this.destroyed)throw new d("invalid","This client was destroyed.");if(!this.features.call)throw new d("forbidden","Calls are not available on this site.");if(this.call)return this.call;let t=new b(this.apiUrl,this.session,this.agent.id,e);return this.currentCall=t,t.on("state",s=>{s.phase==="ended"&&this.currentCall===t&&this.emit("call",null);}),t.on("error",s=>this.emit("error",s)),this.emit("call",t),await t.start(),t}destroy(){this.destroyed=true,this.currentCall?.hangUp(),this.chat.stop(),this.chat.clear(),this.clear();}};var Pe="0.1.0";
|
|
41
|
+
export{b as Call,R as CharacterXYZ,S as Chat,d as CxError,N as DEFAULT_API_URL,g as Emitter,Pe as VERSION};//# sourceMappingURL=index.js.map
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/audio/player.ts","../src/audio/mic.ts","../src/emitter.ts","../src/errors.ts","../src/http.ts","../src/protocol.ts","../src/call.ts","../src/chat.ts","../src/session.ts","../src/client.ts","../src/index.ts"],"names":["shared","audioContext","PcmPlayer","opts","__publicField","bytes","count","view","buf","ch","i","src","now","delayMs","s","sum","v","WORKLET","levelOf","pcm","openMic","stream","ctx","source","muted","deliver","node","teardown","url","w","e","sp","ratio","pos","out","n","sink","m","t","Emitter","event","fn","_a","payload","CxError","code","message","status","codeForStatus","errorFrom","res","j","send","apiUrl","path","headers","request","readEvents","onEvent","signal","body","reader","decoder","onAbort","value","done","drain","rest","idx","block","data","line","colon","field","raw","parsed","parsePacket","kind","final","o","corrLen","corr","len","BARGE_IN_LEVEL","BARGE_IN_MS","HEARTBEAT_MS","initial","Call","session","agentId","p","patch","level","token","r","err","reason","failures","d","hold","ws","face","emotion","player","old","cid","heardMs","id","was","error","localSeq","localId","Chat","pending","text","mine","reply","finished","failure","x","next","b","memoryStore","k","localStore","RENEW_EARLY_S","SessionManager","info","got","visitorId","DEFAULT_API_URL","CharacterXYZ","_CharacterXYZ","store","call","VERSION"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Plays the agent's streamed voice (PCM16 chunks) gaplessly, and reports how\n * loud it is right now so a UI can draw a ring that follows the voice.\n *\n * Each chunk becomes an AudioBuffer scheduled right after the last one; the\n * first waits a short pre-roll so a slow second chunk does not open a gap.\n */\n\nexport interface PlayerOptions {\n sampleRate?: number;\n onStart?: () => void;\n onEnd?: () => void;\n volume?: number;\n}\n\nconst PREROLL_S = 0.12;\n\nlet shared: AudioContext | null = null;\n\n/** One output context for the page, created on first use (after a gesture). */\nexport function audioContext(): AudioContext {\n if (!shared || shared.state === 'closed') shared = new AudioContext({ latencyHint: 'interactive' });\n if (shared.state === 'suspended') void shared.resume().catch(() => {});\n return shared;\n}\n\nexport class PcmPlayer {\n private readonly ctx: AudioContext;\n private readonly gain: GainNode;\n private readonly analyser: AnalyserNode;\n private readonly data: Uint8Array<ArrayBuffer>;\n private nextAt = 0;\n private started = false;\n private ended = false;\n private finishing = false;\n private sources = new Set<AudioBufferSourceNode>();\n private startedAt = 0;\n readonly sampleRate: number;\n\n constructor(private readonly opts: PlayerOptions = {}) {\n this.ctx = audioContext();\n this.sampleRate = opts.sampleRate ?? 16_000;\n this.gain = this.ctx.createGain();\n this.gain.gain.value = opts.volume ?? 1;\n this.analyser = this.ctx.createAnalyser();\n this.analyser.fftSize = 512;\n this.data = new Uint8Array(new ArrayBuffer(this.analyser.fftSize));\n this.gain.connect(this.analyser).connect(this.ctx.destination);\n }\n\n /** Queue PCM16 little-endian mono bytes. */\n enqueue(bytes: Uint8Array): void {\n if (this.ended || bytes.byteLength < 2) return;\n const count = Math.floor(bytes.byteLength / 2);\n const view = new DataView(bytes.buffer, bytes.byteOffset, count * 2);\n const buf = this.ctx.createBuffer(1, count, this.sampleRate);\n const ch = buf.getChannelData(0);\n for (let i = 0; i < count; i++) ch[i] = view.getInt16(i * 2, true) / 32768;\n const src = this.ctx.createBufferSource();\n src.buffer = buf;\n src.connect(this.gain);\n const now = this.ctx.currentTime;\n if (this.nextAt < now) this.nextAt = now + (this.started ? 0.02 : PREROLL_S);\n src.start(this.nextAt);\n if (!this.started) {\n this.started = true;\n const delayMs = Math.max(0, (this.nextAt - now) * 1000);\n this.startedAt = performance.now() + delayMs;\n setTimeout(() => this.opts.onStart?.(), delayMs);\n }\n this.nextAt += buf.duration;\n this.sources.add(src);\n src.onended = () => {\n this.sources.delete(src);\n if (this.finishing && this.sources.size === 0) this.finish();\n };\n }\n\n /** No more chunks: report the end once the queue has played out. */\n end(): void {\n this.finishing = true;\n if (this.sources.size === 0) this.finish();\n }\n\n /** Silence now (an interruption). Does not call `onEnd`. */\n stop(): void {\n this.ended = true;\n for (const s of this.sources) {\n try {\n s.stop();\n } catch {\n /* not started */\n }\n }\n this.sources.clear();\n this.gain.disconnect();\n }\n\n /** Milliseconds of audio actually heard so far. */\n playedMs(): number {\n return this.started ? Math.max(0, performance.now() - this.startedAt) : 0;\n }\n\n /** Loudness now, 0..1. */\n level(): number {\n this.analyser.getByteTimeDomainData(this.data);\n let sum = 0;\n for (let i = 0; i < this.data.length; i++) {\n const v = (this.data[i]! - 128) / 128;\n sum += v * v;\n }\n return Math.min(1, Math.sqrt(sum / this.data.length) * 3);\n }\n\n private finish() {\n if (this.ended) return;\n this.ended = true;\n this.gain.disconnect();\n this.opts.onEnd?.();\n }\n}\n","/**\n * The microphone as the agent socket wants it: 16 kHz mono PCM16, 30 ms\n * (480-sample) frames, sent continuously.\n *\n * Resampled in an AudioWorklet from whatever rate the device runs at. A\n * context forced to 16 kHz would be simpler and is refused by Firefox for a\n * MediaStream source at another rate, so the worklet does it.\n */\n\nexport const TARGET_RATE = 16_000;\nexport const FRAME_SAMPLES = 480;\n\nconst WORKLET = `\nclass CxyzMic extends AudioWorkletProcessor {\n constructor(o) {\n super();\n this.ratio = sampleRate / ${TARGET_RATE};\n this.pos = 0;\n this.lp = 0;\n this.alpha = Math.min(1, 2 * Math.PI * 7000 / sampleRate / (1 + 2 * Math.PI * 7000 / sampleRate));\n this.out = new Int16Array(${FRAME_SAMPLES});\n this.n = 0;\n }\n process(inputs) {\n const ch = inputs[0] && inputs[0][0];\n if (!ch) return true;\n for (let i = 0; i < ch.length; i++) {\n this.lp += this.alpha * (ch[i] - this.lp);\n this.pos += 1;\n if (this.pos >= this.ratio) {\n this.pos -= this.ratio;\n const s = Math.max(-1, Math.min(1, this.lp));\n this.out[this.n++] = s < 0 ? s * 0x8000 : s * 0x7fff;\n if (this.n === ${FRAME_SAMPLES}) {\n this.port.postMessage(this.out.buffer, [this.out.buffer]);\n this.out = new Int16Array(${FRAME_SAMPLES});\n this.n = 0;\n }\n }\n }\n return true;\n }\n}\nregisterProcessor('cxyz-mic', CxyzMic);\n`;\n\nexport interface MicOptions {\n onFrame: (pcm: ArrayBuffer, level: number) => void;\n deviceId?: string;\n}\n\nexport interface Mic {\n stop(): void;\n setMuted(m: boolean): void;\n readonly muted: boolean;\n}\n\n/** RMS of a PCM16 frame, 0..1. */\nexport function levelOf(pcm: ArrayBuffer): number {\n const s = new Int16Array(pcm);\n if (!s.length) return 0;\n let sum = 0;\n for (let i = 0; i < s.length; i++) {\n const v = s[i]! / 32768;\n sum += v * v;\n }\n return Math.sqrt(sum / s.length);\n}\n\nexport async function openMic(opts: MicOptions): Promise<Mic> {\n if (!navigator.mediaDevices?.getUserMedia) throw new Error('This browser cannot use a microphone here.');\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n deviceId: opts.deviceId ? { exact: opts.deviceId } : undefined,\n channelCount: 1,\n // The agent's voice comes out of the speakers; without cancellation it\n // would hear itself and answer.\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n const ctx = new AudioContext({ latencyHint: 'interactive' });\n const source = ctx.createMediaStreamSource(stream);\n let muted = false;\n const deliver = (buf: ArrayBuffer) => {\n if (muted) {\n // Silence, not nothing: the server keeps a pre-roll of the last frames\n // and splices it onto the next utterance.\n opts.onFrame(new ArrayBuffer(buf.byteLength), 0);\n return;\n }\n opts.onFrame(buf, levelOf(buf));\n };\n\n let node: AudioNode;\n let teardown: () => void;\n try {\n const url = URL.createObjectURL(new Blob([WORKLET], { type: 'application/javascript' }));\n try {\n await ctx.audioWorklet.addModule(url);\n } finally {\n URL.revokeObjectURL(url);\n }\n const w = new AudioWorkletNode(ctx, 'cxyz-mic');\n w.port.onmessage = (e) => deliver(e.data as ArrayBuffer);\n node = w;\n teardown = () => {\n w.port.onmessage = null;\n };\n } catch {\n // A strict Content-Security-Policy can refuse a blob: worklet. The old\n // ScriptProcessor path is deprecated but universal.\n const sp = ctx.createScriptProcessor(4096, 1, 1);\n const ratio = ctx.sampleRate / TARGET_RATE;\n let pos = 0;\n let out = new Int16Array(FRAME_SAMPLES);\n let n = 0;\n sp.onaudioprocess = (e) => {\n const ch = e.inputBuffer.getChannelData(0);\n for (let i = 0; i < ch.length; i++) {\n pos += 1;\n if (pos >= ratio) {\n pos -= ratio;\n const s = Math.max(-1, Math.min(1, ch[i]!));\n out[n++] = s < 0 ? s * 0x8000 : s * 0x7fff;\n if (n === FRAME_SAMPLES) {\n deliver(out.buffer);\n out = new Int16Array(FRAME_SAMPLES);\n n = 0;\n }\n }\n }\n };\n node = sp;\n teardown = () => {\n sp.onaudioprocess = null;\n };\n }\n source.connect(node);\n // A worklet/processor only runs while connected to the destination; a gain\n // of zero keeps the room from hearing itself.\n const sink = ctx.createGain();\n sink.gain.value = 0;\n node.connect(sink).connect(ctx.destination);\n if (ctx.state === 'suspended') await ctx.resume().catch(() => {});\n\n return {\n get muted() {\n return muted;\n },\n setMuted(m: boolean) {\n muted = m;\n for (const t of stream.getAudioTracks()) t.enabled = !m;\n },\n stop() {\n teardown();\n try {\n source.disconnect();\n node.disconnect();\n } catch {\n /* already disconnected */\n }\n for (const t of stream.getTracks()) t.stop();\n void ctx.close().catch(() => {});\n },\n };\n}\n","/** A tiny typed event emitter. `on` returns the unsubscribe. */\nexport class Emitter<Events extends Record<string, unknown>> {\n private handlers: { [K in keyof Events]?: Set<(payload: Events[K]) => void> } = {};\n\n on<K extends keyof Events>(event: K, fn: (payload: Events[K]) => void): () => void {\n (this.handlers[event] ??= new Set()).add(fn);\n return () => this.handlers[event]?.delete(fn);\n }\n\n emit<K extends keyof Events>(event: K, payload: Events[K]): void {\n for (const fn of this.handlers[event] ?? []) {\n try {\n fn(payload);\n } catch (e) {\n // A listener's bug must never break the SDK's own state machine.\n console.error('[characterxyz] listener threw', e);\n }\n }\n }\n\n clear(): void {\n this.handlers = {};\n }\n}\n","export type CxErrorCode =\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'invalid'\n | 'rate_limited'\n | 'payment_required'\n | 'unavailable'\n | 'network'\n | 'unknown';\n\n/** Every failure the SDK reports, with a message fit to show a visitor. */\nexport class CxError extends Error {\n readonly code: CxErrorCode;\n readonly status: number;\n\n constructor(code: CxErrorCode, message: string, status = 0) {\n super(message);\n this.name = 'CxError';\n this.code = code;\n this.status = status;\n }\n}\n\nexport function codeForStatus(status: number): CxErrorCode {\n switch (status) {\n case 401:\n return 'unauthorized';\n case 403:\n return 'forbidden';\n case 404:\n return 'not_found';\n case 402:\n return 'payment_required';\n case 422:\n return 'invalid';\n case 429:\n return 'rate_limited';\n case 503:\n return 'unavailable';\n default:\n return 'unknown';\n }\n}\n","import { CxError, codeForStatus } from './errors.js';\n\nexport interface RequestOptions {\n method?: string;\n body?: unknown;\n token?: string;\n signal?: AbortSignal;\n}\n\nasync function errorFrom(res: Response): Promise<CxError> {\n let message = '';\n try {\n const j = (await res.json()) as { message?: unknown };\n if (typeof j?.message === 'string') message = j.message;\n } catch {\n // not JSON: the status says enough\n }\n return new CxError(codeForStatus(res.status), message || `Request failed (${res.status})`, res.status);\n}\n\nexport async function send(apiUrl: string, path: string, opts: RequestOptions = {}): Promise<Response> {\n const headers: Record<string, string> = {};\n if (opts.body !== undefined) headers['Content-Type'] = 'application/json';\n if (opts.token) headers.Authorization = `Bearer ${opts.token}`;\n let res: Response;\n try {\n res = await fetch(apiUrl + path, {\n method: opts.method ?? (opts.body === undefined ? 'GET' : 'POST'),\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n signal: opts.signal,\n // No cookies, ever: the SDK authenticates with its own bearer token, and\n // a credentialed request would carry the brand page's cookies to us.\n credentials: 'omit',\n cache: 'no-store',\n });\n } catch (e) {\n if ((e as Error)?.name === 'AbortError') throw e;\n throw new CxError('network', 'Could not reach Character XYZ. Check your connection.');\n }\n if (!res.ok) throw await errorFrom(res);\n return res;\n}\n\n/** JSON request; unwraps the API's `{message, data}` envelope. */\nexport async function request<T>(apiUrl: string, path: string, opts: RequestOptions = {}): Promise<T> {\n const res = await send(apiUrl, path, opts);\n const j = (await res.json()) as { data?: T };\n return j.data as T;\n}\n\nexport interface ServerEvent {\n event: string;\n data: unknown;\n}\n\n/**\n * Read a `text/event-stream` body, calling `onEvent` per event, until the\n * stream ends or `signal` aborts. Fetch-based on purpose: `EventSource` cannot\n * send an Authorization header, so it would need the token in the URL.\n */\nexport async function readEvents(res: Response, onEvent: (e: ServerEvent) => void, signal?: AbortSignal): Promise<void> {\n const body = res.body;\n if (!body) return;\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buf = '';\n const onAbort = () => void reader.cancel().catch(() => {});\n signal?.addEventListener('abort', onAbort);\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n buf = drain(buf, onEvent);\n }\n buf += decoder.decode();\n drain(buf + '\\n\\n', onEvent);\n } finally {\n signal?.removeEventListener('abort', onAbort);\n }\n}\n\n/** Dispatch every complete event in `buf`; return what is left over. */\nexport function drain(buf: string, onEvent: (e: ServerEvent) => void): string {\n const normalised = buf.replace(/\\r\\n/g, '\\n');\n let rest = normalised;\n let idx: number;\n while ((idx = rest.indexOf('\\n\\n')) !== -1) {\n const block = rest.slice(0, idx);\n rest = rest.slice(idx + 2);\n let event = 'message';\n const data: string[] = [];\n for (const line of block.split('\\n')) {\n if (!line || line.startsWith(':')) continue;\n const colon = line.indexOf(':');\n const field = colon === -1 ? line : line.slice(0, colon);\n const value = colon === -1 ? '' : line.slice(colon + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n else if (field === 'data') data.push(value);\n }\n if (!data.length) continue;\n const raw = data.join('\\n');\n let parsed: unknown = raw;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // plain text data\n }\n onEvent({ event, data: parsed });\n }\n return rest;\n}\n","/**\n * The agent socket's binary packet (the same one the Stage reads):\n *\n * \"CXYZ\" | version u8 (1) | kind u8 | flags u8 (bit 0 = final)\n * | corrLen u16 | corr utf8 | seq u32 | timestamp u64 | duration u32\n * | payloadLen u32 | payload\n *\n * All little-endian. Kind 1 is voice (PCM16), kind 2/3 are face data, which\n * this SDK does not draw yet.\n */\nexport interface Packet {\n kind: number;\n final: boolean;\n corr: string;\n payload: Uint8Array;\n}\n\nexport function parsePacket(buf: ArrayBuffer): Packet | null {\n if (buf.byteLength < 25) return null;\n const v = new DataView(buf);\n if (v.getUint8(0) !== 0x43 || v.getUint8(1) !== 0x58 || v.getUint8(2) !== 0x59 || v.getUint8(3) !== 0x5a) return null;\n if (v.getUint8(4) !== 1) return null;\n const kind = v.getUint8(5);\n const final = (v.getUint8(6) & 1) !== 0;\n let o = 7;\n const corrLen = v.getUint16(o, true);\n o += 2;\n if (o + corrLen + 20 > buf.byteLength) return null;\n const corr = new TextDecoder().decode(new Uint8Array(buf, o, corrLen));\n o += corrLen + 4 + 8 + 4;\n const len = v.getUint32(o, true);\n o += 4;\n if (o + len > buf.byteLength) return null;\n return { kind, final, corr, payload: new Uint8Array(buf, o, len) };\n}\n\n/** Build one (for tests and tools). */\nexport function buildPacket(p: { kind: number; final: boolean; corr: string; payload: Uint8Array }): ArrayBuffer {\n const corr = new TextEncoder().encode(p.corr);\n const head = 7 + 2 + corr.length + 4 + 8 + 4 + 4;\n const buf = new ArrayBuffer(head + p.payload.byteLength);\n const v = new DataView(buf);\n const bytes = new Uint8Array(buf);\n bytes.set([0x43, 0x58, 0x59, 0x5a], 0);\n v.setUint8(4, 1);\n v.setUint8(5, p.kind);\n v.setUint8(6, p.final ? 1 : 0);\n let o = 7;\n v.setUint16(o, corr.length, true);\n o += 2;\n bytes.set(corr, o);\n o += corr.length + 4 + 8 + 4;\n v.setUint32(o, p.payload.byteLength, true);\n o += 4;\n bytes.set(p.payload, o);\n return buf;\n}\n","import { audioContext, PcmPlayer } from './audio/player.js';\nimport { openMic, type Mic } from './audio/mic.js';\nimport { Emitter } from './emitter.js';\nimport { CxError } from './errors.js';\nimport { readEvents, request, send } from './http.js';\nimport { parsePacket } from './protocol.js';\nimport type { SessionManager } from './session.js';\nimport type { CallEndReason, CallState, Caption } from './types.js';\n\nexport interface CallEvents extends Record<string, unknown> {\n state: CallState;\n /** The visitor's words and the agent's reply, as they are recognised. */\n caption: Caption;\n /** A caption the server withdrew (the visitor was not finished). */\n captionRemoved: string;\n /** The turn is ready: accept() within `holdSeconds`. */\n ready: { holdSeconds: number };\n /** One streamed face batch (kind-3 msgpack payload) for line `corr` — only with `face`. */\n face: { corr: string; payload: Uint8Array };\n /** A line of the agent's voice became audible, or ended (naturally or interrupted). */\n line: { corr: string; event: 'audible' | 'end' };\n error: CxError;\n}\n\nexport interface CallOptions {\n /** Join the moment it is this visitor's turn (default true). */\n autoAccept?: boolean;\n deviceId?: string;\n /**\n * Ask for the agent's face streamed with the voice (Neural Lip Sync), for a\n * UI that draws it. `emotion()` is read when the call connects: the face's\n * mood as the face service takes it (`joy:0.3`), or null for neutral.\n */\n face?: { emotion?: () => string | null };\n}\n\n/** Talking over the agent this loud, this long, stops her. */\nconst BARGE_IN_LEVEL = 0.09;\nconst BARGE_IN_MS = 350;\nconst HEARTBEAT_MS = 25_000;\n\nconst initial = (): CallState => ({\n phase: 'idle',\n callId: null,\n position: null,\n etaSeconds: null,\n holdSeconds: null,\n maxSeconds: null,\n startedAt: null,\n endReason: null,\n muted: false,\n speaking: false,\n agentState: 'idle',\n error: null,\n});\n\n/**\n * One voice call: join the line, wait (chatting is fine meanwhile), accept,\n * talk, hang up. A call is single-use; start another for the next one.\n */\nexport class Call extends Emitter<CallEvents> {\n private s: CallState = initial();\n private ticket: string | null = null;\n private eventsAbort: AbortController | null = null;\n private ws: WebSocket | null = null;\n private mic: Mic | null = null;\n private players = new Map<string, PcmPlayer>();\n private sampleRates = new Map<string, number>();\n private cancelled = new Set<string>();\n private speakingCorr: string | null = null;\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n private loudSince: number | null = null;\n\n constructor(\n private readonly apiUrl: string,\n private readonly session: SessionManager,\n private readonly agentId: string,\n private readonly opts: CallOptions = {},\n ) {\n super();\n }\n\n get state(): CallState {\n return this.s;\n }\n\n /** The line being voiced now, and how much of it has been heard (ms). */\n audible(): { corr: string; ms: number } | null {\n const corr = this.speakingCorr;\n const p = corr ? this.players.get(corr) : undefined;\n return corr && p ? { corr, ms: p.playedMs() } : null;\n }\n\n /** Loudness of the agent's voice right now, 0..1. */\n voiceLevel(): number {\n const p = this.speakingCorr ? this.players.get(this.speakingCorr) : undefined;\n return p ? p.level() : 0;\n }\n\n private set(patch: Partial<CallState>) {\n this.s = { ...this.s, ...patch };\n this.emit('state', this.s);\n }\n\n /**\n * Call from a click: it unlocks audio, asks for the microphone, then joins\n * the line (or goes straight through when a slot is free).\n */\n async start(): Promise<void> {\n if (this.s.phase !== 'idle') return;\n this.set({ phase: 'joining' });\n // Created inside the gesture, or the browser keeps it suspended.\n audioContext();\n try {\n this.mic = await openMic({ deviceId: this.opts.deviceId, onFrame: (pcm, level) => this.onMicFrame(pcm, level) });\n } catch {\n this.finish('mic-denied', 'Allow the microphone to talk, or chat instead.');\n return;\n }\n try {\n const token = await this.session.token();\n const r = await request<{ callId: string; state: string; position?: number; etaSeconds?: number }>(this.apiUrl, '/sdk/v1/calls', {\n method: 'POST',\n body: {},\n token,\n });\n this.set({ callId: r.callId, phase: r.state === 'ready' ? 'joining' : 'queued', position: r.position ?? null, etaSeconds: r.etaSeconds ?? null });\n void this.follow();\n } catch (e) {\n const err = e instanceof CxError ? e : new CxError('unknown', 'Could not start the call.');\n const reason: CallEndReason = err.code === 'rate_limited' ? 'busy' : 'unavailable';\n this.finish(reason, err.message);\n this.emit('error', err);\n }\n }\n\n /** Follow the call's server-side state, reconnecting the stream if it drops. */\n private async follow(): Promise<void> {\n let failures = 0;\n while (this.s.callId && this.s.phase !== 'ended' && this.s.phase !== 'idle') {\n this.eventsAbort = new AbortController();\n try {\n const token = await this.session.token();\n const res = await send(this.apiUrl, `/sdk/v1/calls/${encodeURIComponent(this.s.callId)}/events`, { token, signal: this.eventsAbort.signal });\n failures = 0;\n await readEvents(res, (e) => this.onServerEvent(e.event, e.data as Record<string, unknown>), this.eventsAbort.signal);\n } catch (e) {\n if ((e as Error)?.name === 'AbortError') return;\n if (e instanceof CxError && e.code === 'not_found') {\n this.finish('failed', 'The call ended.');\n return;\n }\n failures += 1;\n if (failures > 5) {\n this.finish('failed', 'Lost the connection to the call.');\n return;\n }\n }\n if (this.ended()) return;\n await new Promise((r) => setTimeout(r, Math.min(4000, 500 * 2 ** failures)));\n }\n }\n\n private onServerEvent(event: string, d: Record<string, unknown>) {\n switch (event) {\n case 'queued':\n if (this.s.phase === 'joining' || this.s.phase === 'queued') {\n this.set({ phase: 'queued', position: Number(d.position) || 1, etaSeconds: Number(d.etaSeconds) || null });\n }\n break;\n case 'ready': {\n if (typeof d.ticket === 'string' && d.ticket) this.ticket = d.ticket;\n const hold = Number(d.holdSeconds) || 0;\n if (this.s.phase !== 'ready' && this.s.phase !== 'connecting' && this.s.phase !== 'live') {\n this.set({ phase: 'ready', holdSeconds: hold, position: null, etaSeconds: null });\n this.emit('ready', { holdSeconds: hold });\n if (this.opts.autoAccept !== false) this.accept();\n } else if (this.s.phase === 'ready') {\n this.set({ holdSeconds: hold });\n }\n break;\n }\n case 'live':\n this.set({ phase: 'live', maxSeconds: Number(d.maxSeconds) || null, startedAt: this.s.startedAt ?? Date.now() - (Number(d.elapsedSeconds) || 0) * 1000 });\n break;\n case 'ended':\n this.finish((String(d.reason || 'hangup') as CallEndReason) || 'hangup', null);\n break;\n }\n }\n\n // A method, not an inline comparison: the phase changes across an await,\n // which TypeScript's narrowing cannot see.\n private ended(): boolean {\n return this.s.phase === 'ended';\n }\n\n /** Take the call now that it is this visitor's turn. */\n accept(): void {\n if (this.s.phase !== 'ready' || !this.ticket || this.ws) return;\n this.set({ phase: 'connecting' });\n const url = this.apiUrl.replace(/^http/, 'ws') + '/sdk/v1/calls/socket';\n const ws = new WebSocket(url, [`cxyz-ticket.${this.ticket}`]);\n this.ticket = null;\n ws.binaryType = 'arraybuffer';\n this.ws = ws;\n ws.onopen = () => {\n const face = this.opts.face;\n const emotion = face?.emotion?.() ?? null;\n ws.send(\n JSON.stringify({\n type: 'agent_identity',\n agent_id: this.agentId,\n skin_index: 0,\n blendshapes: !!face,\n ...(face ? { blendshape_stream: true } : {}),\n ...(face && emotion ? { face_emotion: emotion } : {}),\n }),\n );\n // This page does not gate the microphone: the server's own voice\n // detection judges every frame.\n ws.send(JSON.stringify({ type: 'mic_state', silero: 'off', denoise: false }));\n this.heartbeat = setInterval(() => this.sendJson({ type: 'heartbeat' }), HEARTBEAT_MS);\n this.set({ phase: 'live', startedAt: this.s.startedAt ?? Date.now() });\n };\n ws.onmessage = (e) => this.onSocket(e.data);\n ws.onclose = () => {\n this.ws = null;\n // The event stream says why; give it a moment before calling it ourselves.\n setTimeout(() => {\n if (this.s.phase === 'live' || this.s.phase === 'connecting') this.finish('hangup', null);\n }, 1500);\n };\n }\n\n private sendJson(o: unknown) {\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(o));\n }\n\n private onMicFrame(pcm: ArrayBuffer, level: number) {\n const ws = this.ws;\n if (!ws || ws.readyState !== WebSocket.OPEN) return;\n if (this.speakingCorr) {\n // The agent must not hear itself: while she talks the frames go up as\n // silence, unless the visitor is clearly talking over her.\n const now = performance.now();\n if (level > BARGE_IN_LEVEL) {\n this.loudSince ??= now;\n if (now - this.loudSince >= BARGE_IN_MS) {\n this.loudSince = null;\n this.interrupt();\n ws.send(pcm);\n return;\n }\n } else {\n this.loudSince = null;\n }\n ws.send(new ArrayBuffer(pcm.byteLength));\n return;\n }\n ws.send(pcm);\n }\n\n private onSocket(data: unknown) {\n if (data instanceof ArrayBuffer) {\n const p = parsePacket(data);\n if (!p || this.cancelled.has(p.corr)) return;\n if (p.kind === 3) {\n // A copy, so the receiver may keep or transfer it.\n if (this.opts.face) this.emit('face', { corr: p.corr, payload: p.payload.slice() });\n return;\n }\n if (p.kind !== 1) return;\n let player = this.players.get(p.corr);\n if (!player) {\n // A new line: whatever was playing is over.\n for (const [c, old] of this.players) {\n old.stop();\n this.players.delete(c);\n }\n const corr = p.corr;\n player = new PcmPlayer({\n sampleRate: this.sampleRates.get(corr) ?? 16_000,\n onStart: () => {\n this.speakingCorr = corr;\n this.set({ speaking: true });\n this.emit('line', { corr, event: 'audible' });\n this.sendJson({ type: 'playback_started', correlationId: corr, timestampMs: Date.now() });\n },\n onEnd: () => {\n this.players.delete(corr);\n if (this.speakingCorr === corr) this.speakingCorr = null;\n this.set({ speaking: false });\n this.emit('line', { corr, event: 'end' });\n this.sendJson({ type: 'playback_ended', correlationId: corr, timestampMs: Date.now(), reason: 'natural' });\n this.sendJson({ type: 'speech_ended' });\n },\n });\n this.players.set(corr, player);\n }\n player.enqueue(p.payload);\n if (p.final) player.end();\n return;\n }\n if (typeof data !== 'string') return;\n let o: Record<string, unknown>;\n try {\n o = JSON.parse(data);\n } catch {\n return;\n }\n if ('AgentSpeechMeta' in o) {\n const m = o.AgentSpeechMeta as { correlation_id?: string; sample_rate?: number };\n if (m?.correlation_id && m.sample_rate) this.sampleRates.set(m.correlation_id, m.sample_rate);\n return;\n }\n if ('InteractorTranscript' in o) {\n const t = o.InteractorTranscript as { correlation_id: string; text: string };\n if (t?.text) this.emit('caption', { id: `v:${t.correlation_id}`, role: 'visitor', text: t.text });\n return;\n }\n if ('AgentReplyTranscript' in o) {\n const t = o.AgentReplyTranscript as { correlation_id: string; text: string };\n if (t?.text && !this.cancelled.has(t.correlation_id)) this.emit('caption', { id: `a:${t.correlation_id}`, role: 'agent', text: t.text });\n return;\n }\n if (o.type === 'turn_cancelled' && typeof o.correlationId === 'string') {\n const cid = o.correlationId;\n this.cancelled.add(cid);\n this.players.get(cid)?.stop();\n this.players.delete(cid);\n this.emit('line', { corr: cid, event: 'end' });\n if (this.speakingCorr === cid) {\n this.speakingCorr = null;\n this.set({ speaking: false });\n }\n this.emit('captionRemoved', `a:${cid}`);\n return;\n }\n if (o.kind === 'agent_status' && typeof o.state === 'string') {\n this.set({ agentState: o.state.toLowerCase() });\n }\n }\n\n /** Stop the agent mid-sentence (the visitor wants to speak). */\n interrupt(): void {\n const corr = this.speakingCorr;\n if (!corr) return;\n const p = this.players.get(corr);\n const heardMs = Math.round(p?.playedMs() ?? 0);\n p?.stop();\n this.players.delete(corr);\n this.cancelled.add(corr);\n this.speakingCorr = null;\n this.set({ speaking: false });\n this.emit('line', { corr, event: 'end' });\n this.sendJson({ type: 'playback_ended', correlationId: corr, timestampMs: Date.now(), reason: 'interrupted' });\n this.sendJson({ type: 'interrupt', correlationId: corr, heardMs, timestampMs: Date.now() });\n }\n\n setMuted(muted: boolean): void {\n this.mic?.setMuted(muted);\n this.set({ muted });\n }\n\n /** Leave the line, or hang up. */\n async hangUp(): Promise<void> {\n const id = this.s.callId;\n const was = this.s.phase;\n this.finish(was === 'live' ? 'hangup' : 'left', null);\n if (!id) return;\n try {\n const token = await this.session.token();\n await send(this.apiUrl, `/sdk/v1/calls/${encodeURIComponent(id)}`, { method: 'DELETE', token });\n } catch {\n // The server notices a closed socket / abandoned line on its own.\n }\n }\n\n private finish(reason: CallEndReason, error: string | null) {\n if (this.s.phase === 'ended') return;\n this.eventsAbort?.abort();\n this.eventsAbort = null;\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = null;\n for (const p of this.players.values()) p.stop();\n this.players.clear();\n this.speakingCorr = null;\n this.mic?.stop();\n this.mic = null;\n const ws = this.ws;\n this.ws = null;\n if (ws && ws.readyState <= WebSocket.OPEN) ws.close(1000);\n this.ticket = null;\n this.set({ phase: 'ended', endReason: reason, speaking: false, holdSeconds: null, error });\n }\n}\n","import { Emitter } from './emitter.js';\nimport { CxError } from './errors.js';\nimport { readEvents, request, send } from './http.js';\nimport type { SessionManager } from './session.js';\nimport type { ChatMessage } from './types.js';\n\nexport interface ChatEvents extends Record<string, unknown> {\n /** The whole list, after any change. */\n messages: ChatMessage[];\n /** True from send until the reply is complete. */\n busy: boolean;\n error: CxError;\n}\n\nlet localSeq = 0;\nconst localId = (p: string) => `${p}_${Date.now().toString(36)}_${(localSeq++).toString(36)}`;\n\n/**\n * Text chat with the agent. History lives on the server, so it follows the\n * visitor across page loads (and, for an identified visitor, devices).\n */\nexport class Chat extends Emitter<ChatEvents> {\n private list: ChatMessage[] = [];\n private loaded = false;\n private busy = false;\n private abort: AbortController | null = null;\n\n constructor(\n private readonly apiUrl: string,\n private readonly session: SessionManager,\n ) {\n super();\n }\n\n get messages(): readonly ChatMessage[] {\n return this.list;\n }\n\n get isBusy(): boolean {\n return this.busy;\n }\n\n private publish() {\n this.list = [...this.list];\n this.emit('messages', this.list);\n }\n\n /** Load earlier messages (once; later calls return what is held). */\n async load(): Promise<readonly ChatMessage[]> {\n if (this.loaded) return this.list;\n const token = await this.session.token();\n const res = await request<{ messages: ChatMessage[] }>(this.apiUrl, '/sdk/v1/chat/messages?limit=50', { token });\n // Anything sent while the history was loading stays after it.\n const pending = this.list;\n this.list = [...(res?.messages ?? []), ...pending];\n this.loaded = true;\n this.publish();\n return this.list;\n }\n\n /**\n * Send a message; the reply streams into `messages` as it is written.\n * Resolves with the finished reply.\n */\n async send(text: string): Promise<ChatMessage> {\n const t = text.trim();\n if (!t) throw new CxError('invalid', 'Say something first.');\n if (this.busy) throw new CxError('rate_limited', 'Wait for the reply first.');\n this.setBusy(true);\n const mine: ChatMessage = { id: localId('local'), role: 'visitor', text: t, createdAt: new Date().toISOString() };\n const reply: ChatMessage = { id: localId('reply'), role: 'agent', text: '', createdAt: new Date().toISOString(), streaming: true };\n this.list.push(mine, reply);\n this.publish();\n\n this.abort = new AbortController();\n try {\n const token = await this.session.token();\n const res = await send(this.apiUrl, '/sdk/v1/chat/messages', { method: 'POST', body: { text: t }, token, signal: this.abort.signal });\n let finished: ChatMessage | null = null;\n let failure: string | null = null;\n await readEvents(\n res,\n ({ event, data }) => {\n const d = data as Record<string, unknown>;\n if (event === 'delta' && typeof d?.text === 'string') {\n reply.text += d.text;\n this.publish();\n } else if (event === 'done') {\n finished = { id: String(d.id), role: 'agent', text: String(d.text ?? reply.text), createdAt: String(d.createdAt ?? reply.createdAt) };\n } else if (event === 'error') {\n failure = typeof d?.message === 'string' ? d.message : 'Something went wrong.';\n }\n },\n this.abort.signal,\n );\n if (failure || !finished) throw new CxError('unknown', failure ?? 'The reply was cut off. Try again.');\n const done: ChatMessage = finished;\n this.replace(reply.id, done);\n return done;\n } catch (e) {\n const err = e instanceof CxError ? e : new CxError('network', 'The reply was cut off. Try again.');\n this.list = this.list.filter((m) => m.id !== reply.id);\n const idx = this.list.findIndex((m) => m.id === mine.id);\n if (idx !== -1) this.list[idx] = { ...mine, failed: true };\n this.publish();\n if ((e as Error)?.name !== 'AbortError') this.emit('error', err);\n throw err;\n } finally {\n this.abort = null;\n this.setBusy(false);\n }\n }\n\n /** Send a failed message again. */\n retry(id: string): Promise<ChatMessage> {\n const m = this.list.find((x) => x.id === id && x.failed);\n if (!m) throw new CxError('not_found', 'Nothing to retry.');\n this.list = this.list.filter((x) => x.id !== id);\n this.publish();\n return this.send(m.text);\n }\n\n /** Stop listening to a reply in progress (the server still finishes it). */\n stop(): void {\n this.abort?.abort();\n }\n\n private replace(id: string, next: ChatMessage) {\n const i = this.list.findIndex((m) => m.id === id);\n if (i !== -1) this.list[i] = next;\n this.publish();\n }\n\n private setBusy(b: boolean) {\n this.busy = b;\n this.emit('busy', b);\n }\n}\n","import { CxError } from './errors.js';\nimport { request } from './http.js';\nimport type { SessionInfo } from './types.js';\n\n/** Where the SDK may remember this browser's anonymous visitor id. */\nexport interface VisitorStore {\n get(key: string): string | null;\n set(key: string, value: string): void;\n}\n\nexport const memoryStore = (): VisitorStore => {\n const m = new Map<string, string>();\n return { get: (k) => m.get(k) ?? null, set: (k, v) => void m.set(k, v) };\n};\n\nexport const localStore = (): VisitorStore => ({\n get(k) {\n try {\n return globalThis.localStorage?.getItem(k) ?? null;\n } catch {\n return null;\n }\n },\n set(k, v) {\n try {\n globalThis.localStorage?.setItem(k, v);\n } catch {\n // private mode / blocked storage: the visitor is simply new each time\n }\n },\n});\n\nexport interface SessionSource {\n apiUrl: string;\n agentId?: string;\n /** Browser path: a publishable key, exchanged from this page's origin. */\n publishableKey?: string;\n /**\n * Server path: your backend mints the session with a secret key (an\n * identified visitor) and hands the token to the page. Called again when\n * the session is about to run out.\n */\n getSessionToken?: () => Promise<string | SessionInfo>;\n store: VisitorStore;\n}\n\n/** Renew this long before expiry. */\nconst RENEW_EARLY_S = 60;\n\n/**\n * Holds the current session, renews it before it runs out, and never runs\n * two renewals at once.\n */\nexport class SessionManager {\n private current: SessionInfo | null = null;\n private inflight: Promise<SessionInfo> | null = null;\n\n constructor(private readonly src: SessionSource) {\n if (!src.publishableKey && !src.getSessionToken) {\n throw new CxError('invalid', 'Pass a publishableKey, or getSessionToken for sessions your server mints.');\n }\n }\n\n private visitorKey(): string {\n // Per key, so two brands on one domain never share a visitor.\n const k = this.src.publishableKey ?? 'server';\n return `cxyz:visitor:${k.slice(-12)}`;\n }\n\n get info(): SessionInfo | null {\n return this.current;\n }\n\n /** A token valid for at least the next minute. */\n async token(): Promise<string> {\n const now = Date.now() / 1000;\n if (this.current && this.current.expiresAt - RENEW_EARLY_S > now) return this.current.token;\n return (await this.refresh()).token;\n }\n\n refresh(): Promise<SessionInfo> {\n this.inflight ??= this.mint().finally(() => {\n this.inflight = null;\n });\n return this.inflight;\n }\n\n private async mint(): Promise<SessionInfo> {\n let info: SessionInfo;\n if (this.src.getSessionToken) {\n const got = await this.src.getSessionToken();\n if (typeof got === 'string') {\n // A bare token: ask the server what it unlocks.\n info = await this.describe(got);\n } else {\n info = got;\n }\n } else {\n const visitorId = this.src.store.get(this.visitorKey()) ?? undefined;\n info = await request<SessionInfo>(this.src.apiUrl, '/sdk/v1/sessions', {\n method: 'POST',\n body: { publishableKey: this.src.publishableKey, agentId: this.src.agentId, visitorId },\n });\n this.src.store.set(this.visitorKey(), info.visitorId);\n }\n this.current = info;\n return info;\n }\n\n /** The session behind a token minted elsewhere (`getSessionToken` returned a string). */\n private async describe(token: string): Promise<SessionInfo> {\n const info = await request<SessionInfo>(this.src.apiUrl, '/sdk/v1/session', { token });\n return { ...info, token };\n }\n}\n","import { Call, type CallOptions } from './call.js';\nimport { Chat } from './chat.js';\nimport { Emitter } from './emitter.js';\nimport { CxError } from './errors.js';\nimport { request } from './http.js';\nimport { localStore, memoryStore, SessionManager, type VisitorStore } from './session.js';\nimport type { AgentCard, Features, SessionInfo } from './types.js';\n\nexport const DEFAULT_API_URL = 'https://api.character.xyz';\n\nexport interface InitOptions {\n /** `cxyz_pk_live_…` — safe in the page; works only from the key's allowed sites. */\n publishableKey?: string;\n /**\n * For signed-in visitors: return a session your server minted with its\n * secret key (see `@characterxyz/server`). Called again before expiry.\n */\n getSessionToken?: () => Promise<string | SessionInfo>;\n /** Which of the key's agents to talk to. Defaults to the key's first. */\n agentId?: string;\n /** Override the API (staging, local development). */\n apiUrl?: string;\n /** Remember the anonymous visitor across visits (default) or not at all. */\n storage?: 'local' | 'memory' | VisitorStore;\n}\n\nexport interface ClientEvents extends Record<string, unknown> {\n /** A call started or ended; the widget swaps its view on this. */\n call: Call | null;\n error: CxError;\n}\n\n/**\n * The headless SDK. `await CharacterXYZ.init({ publishableKey })`, then use\n * `chat` and `startCall()`. Everything the widget does goes through here, so\n * a brand can build its own UI on the same calls.\n */\nexport class CharacterXYZ extends Emitter<ClientEvents> {\n readonly chat: Chat;\n private currentCall: Call | null = null;\n private destroyed = false;\n\n private constructor(\n readonly apiUrl: string,\n private readonly session: SessionManager,\n private info: SessionInfo,\n ) {\n super();\n this.chat = new Chat(apiUrl, session);\n }\n\n static async init(opts: InitOptions): Promise<CharacterXYZ> {\n const apiUrl = (opts.apiUrl ?? DEFAULT_API_URL).replace(/\\/+$/, '');\n if (opts.publishableKey && /^cxyz_sk_/.test(opts.publishableKey)) {\n // A secret key in a page is a leak. Refuse loudly, before it is sent anywhere.\n throw new CxError('invalid', 'That is a SECRET key. Never put it in a web page: use a publishable key (cxyz_pk_…). Revoke the secret key now.');\n }\n const store = opts.storage === 'memory' ? memoryStore() : opts.storage && typeof opts.storage === 'object' ? opts.storage : localStore();\n const session = new SessionManager({ apiUrl, agentId: opts.agentId, publishableKey: opts.publishableKey, getSessionToken: opts.getSessionToken, store });\n const info = await session.refresh();\n return new CharacterXYZ(apiUrl, session, info);\n }\n\n get agent(): AgentCard {\n return (this.session.info ?? this.info).agent;\n }\n\n get features(): Features {\n return (this.session.info ?? this.info).features;\n }\n\n get appearance(): Record<string, unknown> {\n return (this.session.info ?? this.info).appearance ?? {};\n }\n\n get visitorId(): string {\n return (this.session.info ?? this.info).visitorId;\n }\n\n get mode(): 'live' | 'test' {\n return (this.session.info ?? this.info).mode;\n }\n\n /** The call in progress (queued, ready or live), if any. */\n get call(): Call | null {\n return this.currentCall && this.currentCall.state.phase !== 'ended' ? this.currentCall : null;\n }\n\n /**\n * The worn video character's full render data (the public projection the\n * app's Stage reads), for a UI that draws the face — the widget hands it to\n * the app's renderer. Null when the agent wears none.\n */\n async videoAvatar(): Promise<Record<string, unknown> | null> {\n const token = await this.session.token();\n return request<Record<string, unknown> | null>(this.apiUrl, '/sdk/v1/agent/video-avatar', { token });\n }\n\n /** Start a voice call. Call from a click: it needs the microphone and audio unlocked. */\n async startCall(opts: CallOptions = {}): Promise<Call> {\n if (this.destroyed) throw new CxError('invalid', 'This client was destroyed.');\n if (!this.features.call) throw new CxError('forbidden', 'Calls are not available on this site.');\n if (this.call) return this.call;\n const call = new Call(this.apiUrl, this.session, this.agent.id, opts);\n this.currentCall = call;\n call.on('state', (s) => {\n if (s.phase === 'ended' && this.currentCall === call) this.emit('call', null);\n });\n call.on('error', (e) => this.emit('error', e));\n this.emit('call', call);\n await call.start();\n return call;\n }\n\n destroy(): void {\n this.destroyed = true;\n void this.currentCall?.hangUp();\n this.chat.stop();\n this.chat.clear();\n this.clear();\n }\n}\n","/**\n * `@characterxyz/web` — Character XYZ on any web page, headless.\n *\n * ```ts\n * import { CharacterXYZ } from '@characterxyz/web';\n *\n * const cx = await CharacterXYZ.init({ publishableKey: 'cxyz_pk_live_…' });\n * cx.chat.on('messages', render);\n * await cx.chat.send('Hi!');\n *\n * button.onclick = async () => {\n * const call = await cx.startCall();\n * call.on('state', (s) => show(s.phase, s.position));\n * };\n * ```\n *\n * The ready-made widget is `@characterxyz/widget`; this package is what it\n * is built on, for brands who want their own UI.\n */\nexport { CharacterXYZ, DEFAULT_API_URL, type InitOptions, type ClientEvents } from './client.js';\nexport { Chat, type ChatEvents } from './chat.js';\nexport { Call, type CallEvents, type CallOptions } from './call.js';\nexport { CxError, type CxErrorCode } from './errors.js';\nexport { Emitter } from './emitter.js';\nexport type { VisitorStore } from './session.js';\nexport type {\n AgentCard,\n CallEndReason,\n CallPhase,\n CallState,\n Caption,\n ChatMessage,\n Features,\n SessionInfo,\n VideoCharacter,\n VideoClip,\n} from './types.js';\nexport const VERSION = '0.1.0';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@characterxyz/web",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Character XYZ for the web, headless: sessions, streamed chat, voice calls with a fair queue. Framework-free, zero dependencies.",
|
|
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
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/characterxyz/characterxyz-sdk.git",
|
|
30
|
+
"directory": "packages/web"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://character.xyz",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
+
"test": "vitest run"
|
|
37
|
+
}
|
|
6
38
|
}
|