@animated-waffle/client 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 +70 -0
- package/dist/chunk-BXRNROI7.js +1 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +28 -0
- package/dist/internal.js +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Narya.ai
|
|
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
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# `@animated-waffle/client`
|
|
2
|
+
|
|
3
|
+
Framework-independent browser SDK for embedding a published Narya talking
|
|
4
|
+
Agent: connection lifecycle, microphone input, text input, state, and
|
|
5
|
+
transcripts. React applications should use
|
|
6
|
+
[`@animated-waffle/react`](../waffle-react), which re-exports this entire API
|
|
7
|
+
and adds the Avatar renderer.
|
|
8
|
+
|
|
9
|
+
The Agent owns its avatar, voice, and prompt. Pipecat, Daily, API routes, and
|
|
10
|
+
avatar asset URLs are SDK implementation details. Production is the default
|
|
11
|
+
API origin; tests and non-production integrations may pass `apiOrigin`.
|
|
12
|
+
|
|
13
|
+
## Connect
|
|
14
|
+
|
|
15
|
+
Keep the permanent workspace API key on your server. Exchange it for a
|
|
16
|
+
short-lived Agent session token and give the browser a callback that obtains
|
|
17
|
+
one for each connection:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { WaffleClient } from '@animated-waffle/client'
|
|
21
|
+
|
|
22
|
+
const agentId = '22222222-2222-4222-8222-222222222222'
|
|
23
|
+
const endUserId = '55555555-5555-4555-8555-555555555555'
|
|
24
|
+
const waffle = new WaffleClient({
|
|
25
|
+
agentId,
|
|
26
|
+
sessionToken: async () => {
|
|
27
|
+
const response = await fetch('/api/narya-session-token', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({ agentId, endUserId }),
|
|
31
|
+
})
|
|
32
|
+
const body = await response.json()
|
|
33
|
+
return body.token
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
waffle.on('transcript', ({ role, text, final }) => {
|
|
38
|
+
if (final) console.log(role, text)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
await waffle.connect({ inputMode: 'push-to-talk' })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`endUserId` is one stable bare UUID per end user. An anonymous application can
|
|
45
|
+
generate it once with `crypto.randomUUID()` and persist it on that device.
|
|
46
|
+
|
|
47
|
+
To target a non-production environment:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const waffle = new WaffleClient({
|
|
51
|
+
agentId,
|
|
52
|
+
sessionToken: () => getSessionToken(agentId),
|
|
53
|
+
apiOrigin: 'https://animated-waffle-dev.narya.ai',
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API surface
|
|
58
|
+
|
|
59
|
+
- `connect({ inputMode? })` — `'push-to-talk'` (default) or `'automatic'`.
|
|
60
|
+
- `disconnect()`, `sendText(text)`.
|
|
61
|
+
- `startPushToTalk()` / `stopPushToTalk()` / `cancelPushToTalk()`.
|
|
62
|
+
- `on('status' | 'session' | 'transcript' | 'agentSpeaking' | 'error', fn)` —
|
|
63
|
+
returns the unsubscribe function.
|
|
64
|
+
- `status`, `session` getters; failures throw `WaffleError` with `code`.
|
|
65
|
+
|
|
66
|
+
`./internal` is a private contract consumed by `@animated-waffle/react`; it is
|
|
67
|
+
not part of the public API and may change without notice.
|
|
68
|
+
|
|
69
|
+
See the [SDK documentation](https://animated-waffle.narya.ai/docs/sdk) for the
|
|
70
|
+
complete integration guide.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o=new WeakMap;function s(n,t,a){let e=o.get(n)??new Map,r=e.get(t)??new Set;return r.add(a),e.set(t,r),o.set(n,e),()=>r.delete(a)}function i(n,t,a){o.get(n)?.get(t)?.forEach(e=>{e(a)})}export{s as a,i as b};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
type WaffleStatus = 'disconnected' | 'connecting' | 'connected' | 'disconnecting';
|
|
2
|
+
type WaffleInputMode = 'automatic' | 'push-to-talk';
|
|
3
|
+
interface WaffleSession {
|
|
4
|
+
id: string;
|
|
5
|
+
agentId: string;
|
|
6
|
+
avatarId: string;
|
|
7
|
+
inputMode: WaffleInputMode;
|
|
8
|
+
}
|
|
9
|
+
interface WaffleTranscript {
|
|
10
|
+
role: 'user' | 'assistant';
|
|
11
|
+
text: string;
|
|
12
|
+
final: boolean;
|
|
13
|
+
timestamp?: string;
|
|
14
|
+
}
|
|
15
|
+
interface WaffleClientEvents {
|
|
16
|
+
status: WaffleStatus;
|
|
17
|
+
session: WaffleSession | null;
|
|
18
|
+
error: Error;
|
|
19
|
+
agentSpeaking: boolean;
|
|
20
|
+
transcript: WaffleTranscript;
|
|
21
|
+
}
|
|
22
|
+
type WaffleSessionToken = () => string | Promise<string>;
|
|
23
|
+
interface WaffleClientOptions {
|
|
24
|
+
/** The published Agent to connect to. */
|
|
25
|
+
agentId: string;
|
|
26
|
+
/** A short-lived token minted for this Agent by the Narya API. */
|
|
27
|
+
sessionToken: WaffleSessionToken;
|
|
28
|
+
/** Override the Narya API origin for a non-production environment. */
|
|
29
|
+
apiOrigin?: string;
|
|
30
|
+
}
|
|
31
|
+
interface WaffleConnectOptions {
|
|
32
|
+
inputMode?: WaffleInputMode;
|
|
33
|
+
}
|
|
34
|
+
type Listener<K extends keyof WaffleClientEvents> = (payload: WaffleClientEvents[K]) => void;
|
|
35
|
+
declare class WaffleError extends Error {
|
|
36
|
+
readonly status?: number | undefined;
|
|
37
|
+
readonly code?: string | undefined;
|
|
38
|
+
constructor(message: string, status?: number | undefined, code?: string | undefined);
|
|
39
|
+
}
|
|
40
|
+
declare class WaffleClient {
|
|
41
|
+
private readonly realtime;
|
|
42
|
+
private readonly listeners;
|
|
43
|
+
private readonly options;
|
|
44
|
+
private readonly apiOrigin;
|
|
45
|
+
private currentStatus;
|
|
46
|
+
private currentSession;
|
|
47
|
+
private startPromise;
|
|
48
|
+
private stopPromise;
|
|
49
|
+
private requestAbort;
|
|
50
|
+
private audio;
|
|
51
|
+
private activeInputMode;
|
|
52
|
+
private turnId;
|
|
53
|
+
private nextTurnId;
|
|
54
|
+
private lifecycleVersion;
|
|
55
|
+
constructor(options: WaffleClientOptions);
|
|
56
|
+
get status(): WaffleStatus;
|
|
57
|
+
get session(): WaffleSession | null;
|
|
58
|
+
on<K extends keyof WaffleClientEvents>(event: K, listener: Listener<K>): () => void;
|
|
59
|
+
connect(options?: WaffleConnectOptions): Promise<WaffleSession>;
|
|
60
|
+
disconnect(): Promise<void>;
|
|
61
|
+
sendText(text: string): Promise<void>;
|
|
62
|
+
startPushToTalk(): void;
|
|
63
|
+
stopPushToTalk(): void;
|
|
64
|
+
cancelPushToTalk(): void;
|
|
65
|
+
private startInternal;
|
|
66
|
+
private stopInternal;
|
|
67
|
+
private sendInputControl;
|
|
68
|
+
private assertConnected;
|
|
69
|
+
private handleUserTranscript;
|
|
70
|
+
private handleBotOutput;
|
|
71
|
+
private handleTransportState;
|
|
72
|
+
private handleReady;
|
|
73
|
+
private handleDisconnected;
|
|
74
|
+
private setAudioTrack;
|
|
75
|
+
private stopAudio;
|
|
76
|
+
private setStatus;
|
|
77
|
+
private fail;
|
|
78
|
+
private resolveSessionToken;
|
|
79
|
+
private withTimeout;
|
|
80
|
+
private emit;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { WaffleClient, type WaffleClientEvents, type WaffleClientOptions, type WaffleConnectOptions, WaffleError, type WaffleInputMode, type WaffleSession, type WaffleSessionToken, type WaffleStatus, type WaffleTranscript };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as d}from"./chunk-BXRNROI7.js";import{PipecatClient as g}from"@pipecat-ai/client-js";import{DailyTransport as S}from"@pipecat-ai/daily-transport";var w=15e3,T=3e4,y="https://animated-waffle.narya.ai",k=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,I=/^sha256:[a-f0-9]{64}$/,s=class extends Error{constructor(e,n,o){super(e);this.status=n;this.code=o;this.name="WaffleError"}status;code};function p(i){return i!==null&&typeof i=="object"&&!Array.isArray(i)?i:null}function b(i=y){let t;try{t=new URL(i)}catch{throw new s("apiOrigin must be a valid URL.",void 0,"invalid_api_origin")}let e=t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]";if(t.protocol!=="https:"&&!(t.protocol==="http:"&&e)||t.username||t.password||t.pathname!=="/"&&t.pathname!==""||t.search||t.hash)throw new s("apiOrigin must be an HTTPS origin or an HTTP loopback origin.",void 0,"invalid_api_origin");return t.origin}function u(i,t){if(typeof i!="string"||i.trim().length===0)throw new s(`Session response is missing ${t}.`);return i}function _(i){let t=u(i,"avatar.asset_hash");if(!I.test(t))throw new s("Session response contains an invalid Avatar asset hash.");return t}function m(i){return typeof i=="number"&&Number.isFinite(i)?i:void 0}function h(i){return typeof i=="string"&&i.length>0?i:void 0}function A(i,t){let e=p(i);if(!e)throw new s("Session response must be a JSON object.");if(e.protocol_version!==1)throw new s("Session response has an unsupported protocol version.");let n=p(e.connection);if(!n||n.transport!=="webrtc")throw new s("Session response is missing a WebRTC connection.");let o=u(n.url,"connection.url");try{if(new URL(o).protocol!=="https:")throw new Error}catch{throw new s("Session response contains an invalid connection URL.")}let c=u(e.avatar_id,"avatar_id"),a=p(e.avatar);if(!a||u(a.id,"avatar.id")!==c)throw new s("Session response contains mismatched Avatar metadata.");let r=u(a.engine,"avatar.engine");if(r!=="vrm")throw new s("Session response contains an unsupported Avatar engine.");let l=u(a.model_url,"avatar.model_url");try{if(new URL(l).protocol!=="https:")throw new Error}catch{throw new s("Session response contains an invalid Avatar model URL.")}return{id:u(e.session_id,"session_id"),agentId:u(e.agent_id,"agent_id"),avatarId:c,avatar:{id:c,name:u(a.name,"avatar.name"),engine:r,modelUrl:l,assetHash:_(a.asset_hash),runtimeProfile:u(a.runtime_profile,"avatar.runtime_profile")},inputMode:t,room:o,token:u(n.token,"connection.token")}}function C(i){let t=p(i);if(!t||typeof t.type!="string")return null;let e={contextId:h(t.contextId)??null,segmentId:h(t.segmentId),occurrence:m(t.occurrence),audioTime:m(t.audioTime),offset:m(t.offset)};if(t.type==="avatar-emotion"){let n=h(t.emotion);return n?{phase:"emotion",emotion:n,...e}:null}if(t.type==="avatar-vocal-action"){let n=h(t.action);return n?{phase:"vocal-action",action:n,...e}:null}return null}function f(i){let{avatar:t,room:e,token:n,...o}=i;return o}var v=class{realtime;listeners=new Map;options;apiOrigin;currentStatus="disconnected";currentSession=null;startPromise=null;stopPromise=null;requestAbort=null;audio=null;activeInputMode="push-to-talk";turnId=null;nextTurnId=0;lifecycleVersion=0;constructor(t){if(this.options=t,this.apiOrigin=b(t.apiOrigin),!k.test(t.agentId))throw new s("agentId must be a UUID.",void 0,"invalid_agent_id");if(typeof t.sessionToken!="function")throw new s("sessionToken must be a function.",void 0,"invalid_session_token");let e=new S({bufferLocalAudioUntilBotReady:!0,inputSettings:{audio:{processor:{type:"noise-cancellation"}}}}),n={onTransportStateChanged:o=>this.handleTransportState(o),onBotReady:()=>this.handleReady(),onDisconnected:()=>this.handleDisconnected(),onBotStartedSpeaking:()=>this.emit("agentSpeaking",!0),onBotStoppedSpeaking:()=>this.emit("agentSpeaking",!1),onUserTranscript:o=>this.handleUserTranscript(o),onBotOutput:o=>this.handleBotOutput(o),onServerMessage:o=>{let c=C(o);c&&d(this,"avatar",c)},onTrackStarted:(o,c)=>{o.kind==="audio"&&c?.local===!1&&this.setAudioTrack(o)},onTrackStopped:(o,c)=>{o.kind==="audio"&&c?.local===!1&&this.setAudioTrack(null)},onError:o=>this.fail(new s(p(o)?.message?.toString()??"Realtime connection failed."))};this.realtime=new g({transport:e,enableCam:!1,enableMic:!1,disconnectOnBotDisconnect:!0,callbacks:n})}get status(){return this.currentStatus}get session(){return this.currentSession?f(this.currentSession):null}on(t,e){let n=this.listeners.get(t)??new Set;return n.add(e),this.listeners.set(t,n),()=>n.delete(e)}connect(t={}){if(this.currentSession&&this.status==="connected")return Promise.resolve(f(this.currentSession));if(this.startPromise)return this.startPromise;let e=++this.lifecycleVersion,n=this.startInternal(t,e).finally(()=>{this.startPromise===n&&(this.startPromise=null)});return this.startPromise=n,n}disconnect(){if(this.stopPromise)return this.stopPromise;let t=this.stopInternal().finally(()=>{this.stopPromise===t&&(this.stopPromise=null)});return this.stopPromise=t,t}async sendText(t){let e=t.trim();e&&(this.assertConnected(),await this.realtime.sendText(e,{audio_response:!0,run_immediately:!0}))}startPushToTalk(){if(this.turnId===null){this.nextTurnId+=1,this.turnId=this.nextTurnId;try{this.realtime.enableMic(!0),this.sendInputControl("start",this.turnId)}catch(t){throw this.turnId=null,t}}}stopPushToTalk(){this.turnId!==null&&(this.sendInputControl("stop",this.turnId),this.turnId=null)}cancelPushToTalk(){this.turnId!==null&&(this.sendInputControl("cancel",this.turnId),this.turnId=null)}async startInternal(t,e){this.activeInputMode=t.inputMode??"push-to-talk",this.setStatus("connecting");let n=new AbortController;this.requestAbort=n;let o;try{let r=await this.resolveSessionToken();o=await this.withTimeout(fetch(`${this.apiOrigin}/v1/agents/${encodeURIComponent(this.options.agentId)}/sessions`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",Authorization:`Bearer ${r}`},signal:n.signal,body:JSON.stringify({input_mode:this.activeInputMode==="push-to-talk"?"push_to_talk":"automatic"})}),w,"Timed out creating the Waffle session.",()=>n.abort())}catch(r){let l=r instanceof Error?r:new s("Could not create session.");throw e!==this.lifecycleVersion?new s("The connection attempt was cancelled."):(this.fail(l),l)}finally{this.requestAbort===n&&(this.requestAbort=null)}if(e!==this.lifecycleVersion)throw new s("The connection attempt was cancelled.");let c=await o.json().catch(()=>null);if(!o.ok){let r=p(c),l=new s(h(r?.detail)??"Could not create session.",o.status,h(r?.code));throw this.fail(l),l}let a;try{a=A(c,this.activeInputMode)}catch(r){let l=r instanceof Error?r:new s("Could not parse the Waffle session.");throw this.fail(l),l}this.currentSession=a,this.emit("session",f(a)),d(this,"presentation",a.avatar),this.setStatus("connecting");try{await this.withTimeout(this.realtime.connect({url:a.room,token:a.token}).then(()=>{}),T,"Timed out waiting for the Waffle Agent.",()=>{this.realtime.disconnect().catch(()=>{})})}catch(r){this.currentSession=null,this.emit("session",null),d(this,"presentation",null),await this.realtime.disconnect().catch(()=>{});let l=r instanceof Error?r:new s("Could not connect.");throw e!==this.lifecycleVersion?new s("The connection attempt was cancelled."):(this.fail(l),l)}return this.activeInputMode==="automatic"&&this.realtime.enableMic(!0),this.setStatus("connected"),this.setAudioTrack(this.realtime.tracks().bot?.audio??null),f(a)}async stopInternal(){if(this.lifecycleVersion+=1,this.requestAbort?.abort(),this.turnId=null,this.stopAudio(),this.currentStatus!=="disconnected"){this.setStatus("disconnecting");try{await this.realtime.disconnect()}finally{this.currentSession=null,this.emit("session",null),d(this,"presentation",null),this.emit("agentSpeaking",!1),this.setStatus("disconnected")}}}sendInputControl(t,e){if(this.activeInputMode!=="push-to-talk")throw new s('Push-to-talk controls require inputMode: "push-to-talk".');this.assertConnected(),this.realtime.sendClientMessage("voice.input_control",{mode:"push_to_talk",state:t,turnId:e})}assertConnected(){if(this.status!=="connected")throw new s("Start the Waffle session before sending input.")}handleUserTranscript(t){this.emit("transcript",{role:"user",text:t.text,final:t.final,timestamp:t.timestamp})}handleBotOutput(t){this.emit("transcript",{role:"assistant",text:t.text,final:!0})}handleTransportState(t){t==="ready"?this.handleReady():t==="disconnecting"?this.setStatus("disconnecting"):t==="disconnected"?this.handleDisconnected():this.currentSession&&this.currentStatus!=="connected"&&this.setStatus("connecting")}handleReady(){this.setStatus("connected")}handleDisconnected(){this.currentSession=null,this.emit("session",null),d(this,"presentation",null),this.stopAudio(),this.emit("agentSpeaking",!1),this.setStatus("disconnected")}setAudioTrack(t){if(d(this,"audioTrack",t),this.stopAudio(!1),!t||typeof document>"u")return;let e=document.createElement("audio");e.autoplay=!0,e.setAttribute("playsinline",""),e.srcObject=new MediaStream([t]),this.audio=e,e.play().catch(n=>{this.emit("error",n instanceof Error?n:new s("Browser blocked agent audio."))})}stopAudio(t=!0){this.audio&&(this.audio.pause(),this.audio.srcObject=null,this.audio=null),t&&d(this,"audioTrack",null)}setStatus(t){this.currentStatus!==t&&(this.currentStatus=t,this.emit("status",t))}fail(t){this.setStatus("disconnected"),this.emit("error",t)}async resolveSessionToken(){let t=await this.options.sessionToken();if(!t.trim())throw new s("sessionToken must not be empty.",void 0,"invalid_session_token");return t}withTimeout(t,e,n,o){return new Promise((c,a)=>{let r=setTimeout(()=>{o?.(),a(new s(n))},e);t.then(l=>{clearTimeout(r),c(l)},l=>{clearTimeout(r),a(l)})})}emit(t,e){this.listeners.get(t)?.forEach(n=>{n(e)})}};export{v as WaffleClient,s as WaffleError};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface InternalAvatarEvent {
|
|
2
|
+
phase: 'emotion' | 'vocal-action';
|
|
3
|
+
contextId?: string | null;
|
|
4
|
+
emotion?: string;
|
|
5
|
+
action?: string;
|
|
6
|
+
segmentId?: string;
|
|
7
|
+
occurrence?: number;
|
|
8
|
+
audioTime?: number;
|
|
9
|
+
offset?: number;
|
|
10
|
+
}
|
|
11
|
+
interface InternalAvatarPresentation {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
engine: 'vrm';
|
|
15
|
+
modelUrl: string;
|
|
16
|
+
assetHash: string;
|
|
17
|
+
runtimeProfile: string;
|
|
18
|
+
}
|
|
19
|
+
interface InternalWaffleEvents {
|
|
20
|
+
avatar: InternalAvatarEvent;
|
|
21
|
+
audioTrack: MediaStreamTrack | null;
|
|
22
|
+
presentation: InternalAvatarPresentation | null;
|
|
23
|
+
}
|
|
24
|
+
type InternalListener<K extends keyof InternalWaffleEvents> = (payload: InternalWaffleEvents[K]) => void;
|
|
25
|
+
declare function subscribeInternal<K extends keyof InternalWaffleEvents>(owner: object, event: K, listener: InternalListener<K>): () => void;
|
|
26
|
+
declare function emitInternal<K extends keyof InternalWaffleEvents>(owner: object, event: K, payload: InternalWaffleEvents[K]): void;
|
|
27
|
+
|
|
28
|
+
export { type InternalAvatarEvent, type InternalAvatarPresentation, type InternalWaffleEvents, emitInternal, subscribeInternal };
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b}from"./chunk-BXRNROI7.js";export{b as emitInternal,a as subscribeInternal};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@animated-waffle/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Framework-independent browser SDK for Narya Animated Waffle talking Agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://animated-waffle.narya.ai/docs/sdk",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/NaryaAI/animated-waffle.git",
|
|
12
|
+
"directory": "packages/waffle-client"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./internal": {
|
|
26
|
+
"types": "./dist/internal.d.ts",
|
|
27
|
+
"import": "./dist/internal.js",
|
|
28
|
+
"default": "./dist/internal.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@pipecat-ai/client-js": "1.12.0",
|
|
37
|
+
"@pipecat-ai/daily-transport": "1.6.7"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.5.0",
|
|
41
|
+
"typescript": "^5.7.2",
|
|
42
|
+
"vitest": "^3.0.5"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"test": "vitest run"
|
|
48
|
+
}
|
|
49
|
+
}
|