@komaa/standin-sdk 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 +141 -0
- package/dist/ambient.d.ts +80 -0
- package/dist/ambient.d.ts.map +1 -0
- package/dist/ambient.js +281 -0
- package/dist/ambient.js.map +1 -0
- package/dist/attachments.d.ts +149 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +451 -0
- package/dist/attachments.js.map +1 -0
- package/dist/audio.d.ts +80 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +170 -0
- package/dist/audio.js.map +1 -0
- package/dist/avatar.d.ts +111 -0
- package/dist/avatar.d.ts.map +1 -0
- package/dist/avatar.js +201 -0
- package/dist/avatar.js.map +1 -0
- package/dist/callServer.d.ts +151 -0
- package/dist/callServer.d.ts.map +1 -0
- package/dist/callServer.js +1097 -0
- package/dist/callServer.js.map +1 -0
- package/dist/callTools.d.ts +154 -0
- package/dist/callTools.d.ts.map +1 -0
- package/dist/callTools.js +255 -0
- package/dist/callTools.js.map +1 -0
- package/dist/chat.d.ts +226 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +574 -0
- package/dist/chat.js.map +1 -0
- package/dist/config.d.ts +32 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -0
- package/dist/consult.d.ts +147 -0
- package/dist/consult.d.ts.map +1 -0
- package/dist/consult.js +388 -0
- package/dist/consult.js.map +1 -0
- package/dist/delivery.d.ts +81 -0
- package/dist/delivery.d.ts.map +1 -0
- package/dist/delivery.js +187 -0
- package/dist/delivery.js.map +1 -0
- package/dist/echoGuard.d.ts +56 -0
- package/dist/echoGuard.d.ts.map +1 -0
- package/dist/echoGuard.js +57 -0
- package/dist/echoGuard.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +10 -0
- package/dist/errors.js.map +1 -0
- package/dist/fetch.d.ts +40 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +240 -0
- package/dist/fetch.js.map +1 -0
- package/dist/gate.d.ts +80 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +249 -0
- package/dist/gate.js.map +1 -0
- package/dist/handler.d.ts +283 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +4 -0
- package/dist/handler.js.map +1 -0
- package/dist/hmac.d.ts +32 -0
- package/dist/hmac.d.ts.map +1 -0
- package/dist/hmac.js +108 -0
- package/dist/hmac.js.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/lane.d.ts +92 -0
- package/dist/lane.d.ts.map +1 -0
- package/dist/lane.js +269 -0
- package/dist/lane.js.map +1 -0
- package/dist/lipsync.d.ts +136 -0
- package/dist/lipsync.d.ts.map +1 -0
- package/dist/lipsync.js +310 -0
- package/dist/lipsync.js.map +1 -0
- package/dist/log.d.ts +18 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +20 -0
- package/dist/log.js.map +1 -0
- package/dist/media.d.ts +43 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +190 -0
- package/dist/media.js.map +1 -0
- package/dist/minutes.d.ts +398 -0
- package/dist/minutes.d.ts.map +1 -0
- package/dist/minutes.js +805 -0
- package/dist/minutes.js.map +1 -0
- package/dist/outbound.d.ts +388 -0
- package/dist/outbound.d.ts.map +1 -0
- package/dist/outbound.js +933 -0
- package/dist/outbound.js.map +1 -0
- package/dist/plugins/cartesia/agent.d.ts +58 -0
- package/dist/plugins/cartesia/agent.d.ts.map +1 -0
- package/dist/plugins/cartesia/agent.js +254 -0
- package/dist/plugins/cartesia/agent.js.map +1 -0
- package/dist/plugins/cartesia/cli.d.ts +3 -0
- package/dist/plugins/cartesia/cli.d.ts.map +1 -0
- package/dist/plugins/cartesia/cli.js +10 -0
- package/dist/plugins/cartesia/cli.js.map +1 -0
- package/dist/plugins/cartesia/config.d.ts +30 -0
- package/dist/plugins/cartesia/config.d.ts.map +1 -0
- package/dist/plugins/cartesia/config.js +29 -0
- package/dist/plugins/cartesia/config.js.map +1 -0
- package/dist/plugins/cartesia/handler.d.ts +40 -0
- package/dist/plugins/cartesia/handler.d.ts.map +1 -0
- package/dist/plugins/cartesia/handler.js +142 -0
- package/dist/plugins/cartesia/handler.js.map +1 -0
- package/dist/plugins/cartesia/index.d.ts +6 -0
- package/dist/plugins/cartesia/index.d.ts.map +1 -0
- package/dist/plugins/cartesia/index.js +54 -0
- package/dist/plugins/cartesia/index.js.map +1 -0
- package/dist/plugins/deepgram/agent.d.ts +60 -0
- package/dist/plugins/deepgram/agent.d.ts.map +1 -0
- package/dist/plugins/deepgram/agent.js +302 -0
- package/dist/plugins/deepgram/agent.js.map +1 -0
- package/dist/plugins/deepgram/cli.d.ts +3 -0
- package/dist/plugins/deepgram/cli.d.ts.map +1 -0
- package/dist/plugins/deepgram/cli.js +10 -0
- package/dist/plugins/deepgram/cli.js.map +1 -0
- package/dist/plugins/deepgram/config.d.ts +39 -0
- package/dist/plugins/deepgram/config.d.ts.map +1 -0
- package/dist/plugins/deepgram/config.js +66 -0
- package/dist/plugins/deepgram/config.js.map +1 -0
- package/dist/plugins/deepgram/handler.d.ts +87 -0
- package/dist/plugins/deepgram/handler.d.ts.map +1 -0
- package/dist/plugins/deepgram/handler.js +268 -0
- package/dist/plugins/deepgram/handler.js.map +1 -0
- package/dist/plugins/deepgram/index.d.ts +11 -0
- package/dist/plugins/deepgram/index.d.ts.map +1 -0
- package/dist/plugins/deepgram/index.js +76 -0
- package/dist/plugins/deepgram/index.js.map +1 -0
- package/dist/plugins/echo/cli.d.ts +3 -0
- package/dist/plugins/echo/cli.d.ts.map +1 -0
- package/dist/plugins/echo/cli.js +10 -0
- package/dist/plugins/echo/cli.js.map +1 -0
- package/dist/plugins/echo/index.d.ts +37 -0
- package/dist/plugins/echo/index.d.ts.map +1 -0
- package/dist/plugins/echo/index.js +61 -0
- package/dist/plugins/echo/index.js.map +1 -0
- package/dist/plugins/elevenlabs/agent.d.ts +72 -0
- package/dist/plugins/elevenlabs/agent.d.ts.map +1 -0
- package/dist/plugins/elevenlabs/agent.js +305 -0
- package/dist/plugins/elevenlabs/agent.js.map +1 -0
- package/dist/plugins/elevenlabs/cli.d.ts +3 -0
- package/dist/plugins/elevenlabs/cli.d.ts.map +1 -0
- package/dist/plugins/elevenlabs/cli.js +10 -0
- package/dist/plugins/elevenlabs/cli.js.map +1 -0
- package/dist/plugins/elevenlabs/config.d.ts +27 -0
- package/dist/plugins/elevenlabs/config.d.ts.map +1 -0
- package/dist/plugins/elevenlabs/config.js +42 -0
- package/dist/plugins/elevenlabs/config.js.map +1 -0
- package/dist/plugins/elevenlabs/handler.d.ts +67 -0
- package/dist/plugins/elevenlabs/handler.d.ts.map +1 -0
- package/dist/plugins/elevenlabs/handler.js +419 -0
- package/dist/plugins/elevenlabs/handler.js.map +1 -0
- package/dist/plugins/elevenlabs/index.d.ts +11 -0
- package/dist/plugins/elevenlabs/index.d.ts.map +1 -0
- package/dist/plugins/elevenlabs/index.js +72 -0
- package/dist/plugins/elevenlabs/index.js.map +1 -0
- package/dist/plugins/livekit/cli.d.ts +3 -0
- package/dist/plugins/livekit/cli.d.ts.map +1 -0
- package/dist/plugins/livekit/cli.js +10 -0
- package/dist/plugins/livekit/cli.js.map +1 -0
- package/dist/plugins/livekit/config.d.ts +47 -0
- package/dist/plugins/livekit/config.d.ts.map +1 -0
- package/dist/plugins/livekit/config.js +46 -0
- package/dist/plugins/livekit/config.js.map +1 -0
- package/dist/plugins/livekit/handler.d.ts +59 -0
- package/dist/plugins/livekit/handler.d.ts.map +1 -0
- package/dist/plugins/livekit/handler.js +211 -0
- package/dist/plugins/livekit/handler.js.map +1 -0
- package/dist/plugins/livekit/index.d.ts +6 -0
- package/dist/plugins/livekit/index.d.ts.map +1 -0
- package/dist/plugins/livekit/index.js +68 -0
- package/dist/plugins/livekit/index.js.map +1 -0
- package/dist/plugins/livekit/room.d.ts +117 -0
- package/dist/plugins/livekit/room.d.ts.map +1 -0
- package/dist/plugins/livekit/room.js +449 -0
- package/dist/plugins/livekit/room.js.map +1 -0
- package/dist/plugins/openai/agent.d.ts +74 -0
- package/dist/plugins/openai/agent.d.ts.map +1 -0
- package/dist/plugins/openai/agent.js +264 -0
- package/dist/plugins/openai/agent.js.map +1 -0
- package/dist/plugins/openai/cli.d.ts +3 -0
- package/dist/plugins/openai/cli.d.ts.map +1 -0
- package/dist/plugins/openai/cli.js +10 -0
- package/dist/plugins/openai/cli.js.map +1 -0
- package/dist/plugins/openai/config.d.ts +29 -0
- package/dist/plugins/openai/config.d.ts.map +1 -0
- package/dist/plugins/openai/config.js +37 -0
- package/dist/plugins/openai/config.js.map +1 -0
- package/dist/plugins/openai/handler.d.ts +65 -0
- package/dist/plugins/openai/handler.d.ts.map +1 -0
- package/dist/plugins/openai/handler.js +297 -0
- package/dist/plugins/openai/handler.js.map +1 -0
- package/dist/plugins/openai/index.d.ts +6 -0
- package/dist/plugins/openai/index.d.ts.map +1 -0
- package/dist/plugins/openai/index.js +72 -0
- package/dist/plugins/openai/index.js.map +1 -0
- package/dist/plugins/openclaw/allowlist.d.ts +9 -0
- package/dist/plugins/openclaw/allowlist.d.ts.map +1 -0
- package/dist/plugins/openclaw/allowlist.js +11 -0
- package/dist/plugins/openclaw/allowlist.js.map +1 -0
- package/dist/plugins/openclaw/config.d.ts +50 -0
- package/dist/plugins/openclaw/config.d.ts.map +1 -0
- package/dist/plugins/openclaw/config.js +53 -0
- package/dist/plugins/openclaw/config.js.map +1 -0
- package/dist/plugins/openclaw/handler.d.ts +90 -0
- package/dist/plugins/openclaw/handler.d.ts.map +1 -0
- package/dist/plugins/openclaw/handler.js +146 -0
- package/dist/plugins/openclaw/handler.js.map +1 -0
- package/dist/plugins/openclaw/index.d.ts +55 -0
- package/dist/plugins/openclaw/index.d.ts.map +1 -0
- package/dist/plugins/openclaw/index.js +89 -0
- package/dist/plugins/openclaw/index.js.map +1 -0
- package/dist/plugins/openclaw/openclaw.plugin.json +74 -0
- package/dist/plugins/openclaw/package.json +14 -0
- package/dist/plugins/openclaw/realtime.d.ts +82 -0
- package/dist/plugins/openclaw/realtime.d.ts.map +1 -0
- package/dist/plugins/openclaw/realtime.js +238 -0
- package/dist/plugins/openclaw/realtime.js.map +1 -0
- package/dist/plugins/openclaw/runtime.d.ts +19 -0
- package/dist/plugins/openclaw/runtime.d.ts.map +1 -0
- package/dist/plugins/openclaw/runtime.js +160 -0
- package/dist/plugins/openclaw/runtime.js.map +1 -0
- package/dist/policy.d.ts +38 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +95 -0
- package/dist/policy.js.map +1 -0
- package/dist/protocol.d.ts +44 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +77 -0
- package/dist/protocol.js.map +1 -0
- package/dist/protocolRuntime.d.ts +19 -0
- package/dist/protocolRuntime.d.ts.map +1 -0
- package/dist/protocolRuntime.js +78 -0
- package/dist/protocolRuntime.js.map +1 -0
- package/dist/smoke.d.ts +65 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +293 -0
- package/dist/smoke.js.map +1 -0
- package/dist/startup.d.ts +74 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +112 -0
- package/dist/startup.js.map +1 -0
- package/dist/tile.d.ts +101 -0
- package/dist/tile.d.ts.map +1 -0
- package/dist/tile.js +195 -0
- package/dist/tile.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/dist/vision.d.ts +160 -0
- package/dist/vision.d.ts.map +1 -0
- package/dist/vision.js +301 -0
- package/dist/vision.js.map +1 -0
- package/dist/visionTools.d.ts +237 -0
- package/dist/visionTools.d.ts.map +1 -0
- package/dist/visionTools.js +578 -0
- package/dist/visionTools.js.map +1 -0
- package/dist/voice.d.ts +143 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +403 -0
- package/dist/voice.js.map +1 -0
- package/package.json +129 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seam every StandIn plugin implements.
|
|
3
|
+
*
|
|
4
|
+
* This is the whole contract between the SDK and an agent framework, and it is
|
|
5
|
+
* deliberately five methods wide. {@link CallServer} owns everything that is the
|
|
6
|
+
* same for every framework - the socket StandIn dials, the HMAC handshake and
|
|
7
|
+
* its replay guard, capacity and draining, the frame loop, sequence numbers and
|
|
8
|
+
* the outbound audio timeline, and the two watchdogs that end a call nobody
|
|
9
|
+
* closed. A plugin owns only the part that differs: what to do with a caller's
|
|
10
|
+
* voice, and where the reply comes from.
|
|
11
|
+
*
|
|
12
|
+
* Identical in shape to the Python SDK's `standin.handler`, translated to TS
|
|
13
|
+
* naming (snake_case becomes camelCase). A plugin ported between the two
|
|
14
|
+
* changes only its method names.
|
|
15
|
+
*
|
|
16
|
+
* Writing one:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { CallServer, type CallSession } from "@komaa/standin-sdk";
|
|
20
|
+
*
|
|
21
|
+
* class EchoHandler {
|
|
22
|
+
* #call!: CallSession;
|
|
23
|
+
* async onStart(session: CallSession) { this.#call = session; }
|
|
24
|
+
* async onCallerAudio(pcm: Buffer) { await this.#call.sendAudio(pcm); }
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* const server = new CallServer({ handlerFactory: () => new EchoHandler() });
|
|
28
|
+
* await server.start();
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Every method is optional: the server treats a missing one as a no-op, so a
|
|
32
|
+
* handler that only wants audio implements only `onCallerAudio`. Nothing extends
|
|
33
|
+
* anything.
|
|
34
|
+
*/
|
|
35
|
+
import type { Emotion, SpeechMark } from "./avatar.js";
|
|
36
|
+
import type { SessionStart } from "./protocol.js";
|
|
37
|
+
import type { DisplayImageOptions, VideoFrame, VideoSource } from "./vision.js";
|
|
38
|
+
/**
|
|
39
|
+
* One live Microsoft Teams call, as a handler sees it.
|
|
40
|
+
*
|
|
41
|
+
* Handed to {@link CallHandler.onStart} and valid until the call ends. The
|
|
42
|
+
* server owns the socket; this is the handler's only way to reach it.
|
|
43
|
+
*/
|
|
44
|
+
export interface CallSession {
|
|
45
|
+
/**
|
|
46
|
+
* StandIn's id for this call. Authenticated - it is the value the handshake
|
|
47
|
+
* HMAC signed, not something a caller supplied.
|
|
48
|
+
*/
|
|
49
|
+
readonly callId: string;
|
|
50
|
+
/**
|
|
51
|
+
* The `session.start` that opened the call: caller identity, direction,
|
|
52
|
+
* thread, recording status.
|
|
53
|
+
*/
|
|
54
|
+
readonly start: SessionStart;
|
|
55
|
+
/**
|
|
56
|
+
* Send the agent's voice to the caller.
|
|
57
|
+
*
|
|
58
|
+
* `pcm` is raw PCM16, 16 kHz, mono, little-endian - the same format
|
|
59
|
+
* {@link CallHandler.onCallerAudio} receives. The server owns the sequence
|
|
60
|
+
* number and the outbound timeline, so a handler never tracks either, and a
|
|
61
|
+
* re-published or swapped audio source cannot make timestamps jump backwards.
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
* Whether the Microsoft Teams call is being recorded, right now.
|
|
65
|
+
*
|
|
66
|
+
* One flag, kept current by the server: it starts from
|
|
67
|
+
* `session.start.recordingStatus` and follows every later `recording.status`
|
|
68
|
+
* change, so a plugin never has to re-derive it from the context sentence it
|
|
69
|
+
* happens to have seen.
|
|
70
|
+
*
|
|
71
|
+
* A reported status WINS over the start snapshot, whichever arrives first.
|
|
72
|
+
* `session.start` omits the field when the state was unknown at answer time,
|
|
73
|
+
* and an omitted field is not "not recording": letting the snapshot overwrite
|
|
74
|
+
* a `recording.status` that landed first would shut every recording-gated
|
|
75
|
+
* capability for the whole call, silently.
|
|
76
|
+
*
|
|
77
|
+
* Gate on it before anything that STORES what the caller said or showed with
|
|
78
|
+
* a third party. A recorded call is one the caller was told is being kept; an
|
|
79
|
+
* unrecorded one is not.
|
|
80
|
+
*/
|
|
81
|
+
readonly recordingActive: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Who is speaking now, when StandIn sends unmixed audio.
|
|
84
|
+
*
|
|
85
|
+
* `undefined` on the mixed path, which is most calls, so treat it as a hint
|
|
86
|
+
* rather than as something to depend on. Use it to attribute a transcript, or
|
|
87
|
+
* to tell a model who it is answering in a meeting.
|
|
88
|
+
*/
|
|
89
|
+
readonly speaker: string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* How many people are on the call.
|
|
92
|
+
*
|
|
93
|
+
* Zero until StandIn first says, and it says again whenever somebody joins or
|
|
94
|
+
* leaves. The number behind the "this is a 1:1 call" and "there are N human
|
|
95
|
+
* participants" context sentences, for a plugin that wants to branch on it
|
|
96
|
+
* rather than hand a sentence to a model.
|
|
97
|
+
*/
|
|
98
|
+
readonly participantCount: number;
|
|
99
|
+
/** Whether anything has actually taken this call yet. */
|
|
100
|
+
readonly answered: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Say that an agent has taken the call. Stamped once, never re-stamped.
|
|
103
|
+
*
|
|
104
|
+
* A plugin that joins a room calls this when the agent's own audio track
|
|
105
|
+
* appears, not when a participant connects: monitors, recorders and avatar
|
|
106
|
+
* workers all connect, and none of them is an agent answering. A plugin that
|
|
107
|
+
* never calls it is still covered, because sending audio counts.
|
|
108
|
+
*/
|
|
109
|
+
markAnswered(): void;
|
|
110
|
+
/**
|
|
111
|
+
* How much outbound data the socket has not yet flushed.
|
|
112
|
+
*
|
|
113
|
+
* The number a continuous sender watches to decide whether to drop a frame.
|
|
114
|
+
* Audio and the avatar tile both push on a timer, and a peer that stops
|
|
115
|
+
* reading turns "send everything" into an unbounded buffer.
|
|
116
|
+
*
|
|
117
|
+
* Zero when the transport cannot report it, so treat a zero as "no evidence
|
|
118
|
+
* of backpressure" rather than as proof of an idle socket.
|
|
119
|
+
*/
|
|
120
|
+
readonly bufferedBytes: number;
|
|
121
|
+
/**
|
|
122
|
+
* The outbound audio timeline, in milliseconds.
|
|
123
|
+
*
|
|
124
|
+
* The same clock this call's `audio.frame` messages are stamped with, which is
|
|
125
|
+
* what a video frame must be stamped with too. A wall clock keeps ticking
|
|
126
|
+
* through listening silence while this one does not, so stamping video from a
|
|
127
|
+
* wall clock makes the audio and video drift apart on paper even when they are
|
|
128
|
+
* in step.
|
|
129
|
+
*/
|
|
130
|
+
readonly mediaTimeMs: number;
|
|
131
|
+
sendAudio(pcm: Buffer): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Drop whatever agent audio StandIn still has buffered.
|
|
134
|
+
*
|
|
135
|
+
* The only lever that un-sends audio already handed to the service: it
|
|
136
|
+
* flushes the platform player, so the caller stops hearing the turn they just
|
|
137
|
+
* interrupted. Call it the moment your provider reports the caller started
|
|
138
|
+
* speaking, before you cancel the response upstream - otherwise a barge-in
|
|
139
|
+
* stops the model but the bot keeps talking for the length of the buffer.
|
|
140
|
+
*/
|
|
141
|
+
cancelPlayback(): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* The most recent frame the caller showed, or `undefined` if they have shown
|
|
144
|
+
* nothing.
|
|
145
|
+
*
|
|
146
|
+
* Synchronous, because it reads a value the frame loop already stored: there
|
|
147
|
+
* is no waiting for a frame here, and a handler that wants to know the moment
|
|
148
|
+
* one arrives implements {@link CallHandler.onVideoFrame} instead.
|
|
149
|
+
*
|
|
150
|
+
* With no `source` the screen share wins over the camera, because an agent
|
|
151
|
+
* asked to look is nearly always being asked about what is being shown rather
|
|
152
|
+
* than who is showing it.
|
|
153
|
+
*/
|
|
154
|
+
latestVideoFrame(source?: VideoSource): VideoFrame | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Draw an image on the bot's video tile for a few seconds.
|
|
157
|
+
*
|
|
158
|
+
* The agent's half of the vision lane: a chart it just computed, a page it is
|
|
159
|
+
* quoting, a photo it was asked for. Best-effort and additive, so a service
|
|
160
|
+
* that does not implement it ignores the message rather than failing the call.
|
|
161
|
+
*/
|
|
162
|
+
displayImage(image: Buffer | string, options?: DisplayImageOptions): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Put one frame of continuous video on the bot's tile.
|
|
165
|
+
*
|
|
166
|
+
* The server owns the sequence number and stamps the frame with the outbound
|
|
167
|
+
* AUDIO timeline, exactly as it does for {@link sendAudio}, so the two streams
|
|
168
|
+
* cannot disagree about what time it is.
|
|
169
|
+
*
|
|
170
|
+
* Latest wins and there is no handshake: the first frames start the stream and
|
|
171
|
+
* silence ends it. Pace it and drop under backpressure rather than queueing,
|
|
172
|
+
* which is what `TileStream` is for.
|
|
173
|
+
*/
|
|
174
|
+
sendTileFrame(jpeg: Buffer, width?: number, height?: number): Promise<void>;
|
|
175
|
+
/**
|
|
176
|
+
* Hint the emotion the avatar should wear on the bot's tile.
|
|
177
|
+
*
|
|
178
|
+
* Best-effort and video only: an unknown emotion renders as neutral, and
|
|
179
|
+
* nothing here changes a sample of what the caller hears.
|
|
180
|
+
*/
|
|
181
|
+
express(emotion: Emotion): Promise<void>;
|
|
182
|
+
/**
|
|
183
|
+
* Send the viseme timeline for one utterance, which is what drives lip-sync
|
|
184
|
+
* on the avatar.
|
|
185
|
+
*
|
|
186
|
+
* Real timings from your provider are best. Where there are none, which is
|
|
187
|
+
* every realtime speech-to-speech model, `lipsync.ts` estimates a timeline
|
|
188
|
+
* from the text and spreads it over the audio that turn actually sent: a
|
|
189
|
+
* mouth on a measured clock beats a still one. What is worse than none is a
|
|
190
|
+
* timeline whose DURATION was guessed, from text length or a words-per-minute
|
|
191
|
+
* rate, because that one drifts further out of step with the voice the longer
|
|
192
|
+
* it runs.
|
|
193
|
+
*/
|
|
194
|
+
sendSpeechMarks(marks: Iterable<SpeechMark>): Promise<void>;
|
|
195
|
+
/**
|
|
196
|
+
* Ask for the call to end. Idempotent, and the first reason wins - a cascade
|
|
197
|
+
* of close causes must not overwrite the one that actually ended it.
|
|
198
|
+
*
|
|
199
|
+
* Safe to call from inside {@link CallHandler.onStart} to refuse a call: it
|
|
200
|
+
* returns immediately there rather than deadlocking against teardown, and the
|
|
201
|
+
* close runs once onStart unwinds.
|
|
202
|
+
*/
|
|
203
|
+
end(reason: string): Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* What a plugin implements. One instance per call, built by a
|
|
207
|
+
* {@link HandlerFactory}.
|
|
208
|
+
*
|
|
209
|
+
* Every method is awaited by the server and every one is optional. A rejection
|
|
210
|
+
* from any of them is logged and ends that call alone - one bad call must never
|
|
211
|
+
* take the worker with it.
|
|
212
|
+
*/
|
|
213
|
+
export interface CallHandler {
|
|
214
|
+
/**
|
|
215
|
+
* The call is live. Join a room, open a realtime socket, build an agent -
|
|
216
|
+
* whatever this framework needs. Audio does not flow until this resolves, so a
|
|
217
|
+
* slow start delays the caller rather than dropping frames.
|
|
218
|
+
*/
|
|
219
|
+
onStart?(session: CallSession): void | Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* One frame of the caller's voice: PCM16, 16 kHz, mono, little-endian.
|
|
222
|
+
*
|
|
223
|
+
* Called on the receive path of a live call, so it must not block. The frame
|
|
224
|
+
* has already been validated - a truncated or malformed payload is dropped by
|
|
225
|
+
* the server and never reaches here.
|
|
226
|
+
*/
|
|
227
|
+
onCallerAudio?(pcm: Buffer): void | Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* One sampled frame of the caller's camera or screen share.
|
|
230
|
+
*
|
|
231
|
+
* Optional, and most handlers never implement it: frames arrive sparsely and
|
|
232
|
+
* best-effort, and the common shape is to look only when the model asks, which
|
|
233
|
+
* {@link CallSession.latestVideoFrame} already serves without a callback.
|
|
234
|
+
* Implement this for ambient vision - narrating a slide deck, watching a
|
|
235
|
+
* whiteboard, noticing that the share stopped.
|
|
236
|
+
*
|
|
237
|
+
* Called on the receive path of a live call, so a slow model call belongs off
|
|
238
|
+
* the frame loop, exactly as it does in {@link CallHandler.onCallerAudio}.
|
|
239
|
+
*/
|
|
240
|
+
onVideoFrame?(frame: VideoFrame): void | Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* A different person started speaking.
|
|
243
|
+
*
|
|
244
|
+
* Optional, and only ever called when StandIn sends unmixed audio: most calls
|
|
245
|
+
* carry mixed audio and never call it at all. Called on CHANGE only, never
|
|
246
|
+
* per frame. The name rides every inbound audio frame, and a model told forty
|
|
247
|
+
* times a second who is speaking would hear nothing else.
|
|
248
|
+
*
|
|
249
|
+
* Called on the receive path of a live call, so anything slow belongs off the
|
|
250
|
+
* frame loop, exactly as in {@link CallHandler.onCallerAudio}.
|
|
251
|
+
*/
|
|
252
|
+
onSpeakerChange?(name: string): void | Promise<void>;
|
|
253
|
+
/**
|
|
254
|
+
* Non-interrupting context about the call, as a plain sentence ready to put in
|
|
255
|
+
* front of a model: participant counts and group-call etiquette, DTMF key
|
|
256
|
+
* presses, and recording status changes.
|
|
257
|
+
*
|
|
258
|
+
* Delivered as it arrives. A framework that cannot accept context before its
|
|
259
|
+
* agent is ready should queue it here - the server does not, because what
|
|
260
|
+
* "ready" means is a framework's own business.
|
|
261
|
+
*/
|
|
262
|
+
onContext?(text: string): void | Promise<void>;
|
|
263
|
+
/**
|
|
264
|
+
* StandIn is ending the call and wants this line spoken first.
|
|
265
|
+
*
|
|
266
|
+
* The server has already told StandIn to drop whatever agent audio it had
|
|
267
|
+
* buffered, so this line plays immediately. Interrupt the current turn and say
|
|
268
|
+
* it: the teardown follows shortly, and a goodbye queued behind a long answer
|
|
269
|
+
* is a goodbye the caller never hears.
|
|
270
|
+
*/
|
|
271
|
+
onGoodbye?(text: string): void | Promise<void>;
|
|
272
|
+
/**
|
|
273
|
+
* Release everything this call holds. Always called exactly once, on every
|
|
274
|
+
* path, before the slot is freed.
|
|
275
|
+
*/
|
|
276
|
+
aclose?(reason: string): void | Promise<void>;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Builds one {@link CallHandler} per call. Called with no arguments, so a plugin
|
|
280
|
+
* closes over its own configuration rather than threading it through the server.
|
|
281
|
+
*/
|
|
282
|
+
export type HandlerFactory = () => CallHandler;
|
|
283
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"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"}
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,+BAA+B"}
|
package/dist/hmac.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const TIMESTAMP_HEADER = "x-standin-timestamp";
|
|
2
|
+
export declare const SIGNATURE_HEADER = "x-standin-signature";
|
|
3
|
+
export declare const SIGNATURE_V2_HEADER = "x-standin-signature-v2";
|
|
4
|
+
/** Handshakes are dialed and answered immediately; anything older is a replay. */
|
|
5
|
+
export declare const REPLAY_WINDOW_MS = 60000;
|
|
6
|
+
/** Chat POSTs allow delayed relay retries; WebSocket upgrades still use 60 s. */
|
|
7
|
+
export declare const CHAT_REPLAY_WINDOW_MS = 300000;
|
|
8
|
+
export declare function nowMs(): number;
|
|
9
|
+
/** Signature for a WebSocket upgrade. */
|
|
10
|
+
export declare function signHandshake(secret: string, timestampMs: number | string, handshakeId: string): string;
|
|
11
|
+
/** Constant-time check of an inbound upgrade. Empty inputs fail CLOSED. */
|
|
12
|
+
export declare function verifyHandshake(secret: string, timestamp: string | undefined, handshakeId: string, signature: string | undefined, currentMs?: number): boolean;
|
|
13
|
+
/** Sign a chat POST's exact transmitted bytes as `{timestampMs}.{rawBody}`.
|
|
14
|
+
* Strings are UTF-8 encoded. Serialize once and send those same bytes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function signBody(secret: string, timestampMs: number | string, rawBody: string | Uint8Array): string;
|
|
17
|
+
/** Verify a chat POST, allowing 300 s of clock skew by default.
|
|
18
|
+
* Missing or malformed headers fail closed. The WebSocket chat channel still
|
|
19
|
+
* signs the channel name and uses the separate 60 s window.
|
|
20
|
+
*/
|
|
21
|
+
export declare function verifyBody(secret: string, timestamp: string | undefined, rawBody: string | Uint8Array, signature: string | undefined, currentMs?: number, windowMs?: number): boolean;
|
|
22
|
+
/** Return `METHOD\npath\nsha256_hex(body)` for a v2 control request.
|
|
23
|
+
* The path is the HTTP request path, without the origin or query string,
|
|
24
|
+
* matching the worker verifier. The body covers every field, including tenantId.
|
|
25
|
+
*/
|
|
26
|
+
export declare function canonicalRequest(method: string, path: string, rawBody: string | Uint8Array): string;
|
|
27
|
+
/** Sign an outbound control request for X-StandIn-Signature-V2.
|
|
28
|
+
* Pass the exact bytes you will transmit. v1 handshakes remain supported for
|
|
29
|
+
* WebSockets; control requests should send this v2 header.
|
|
30
|
+
*/
|
|
31
|
+
export declare function signRequest(secret: string, timestampMs: number | string, method: string, path: string, rawBody: string | Uint8Array): string;
|
|
32
|
+
//# sourceMappingURL=hmac.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AACtD,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AACtD,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAE5D,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,SAAU,CAAC;AAE7C,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,WAAW,EAAE,MAAM,GAClB,MAAM,CAIR;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAuBT;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,OAAO,EAAE,MAAM,GAAG,UAAU,GAC3B,MAAM,CAKR;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,SAAwB,GAC/B,OAAO,CAWT;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,UAAU,GAC3B,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,UAAU,GAC3B,MAAM,CAMR"}
|
package/dist/hmac.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright (c) 2026 Komaa DigiTech
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* StandIn signatures for WebSocket handshakes, chat POSTs and control requests.
|
|
5
|
+
*
|
|
6
|
+
* WebSocket handshakes use `HMAC-SHA256(secret, "{timestampMs}.{id}")`,
|
|
7
|
+
* lowercase hex, carried in `X-StandIn-Timestamp` / `X-StandIn-Signature`.
|
|
8
|
+
*
|
|
9
|
+
* inbound StandIn dials the call listener; `id` is the callId in the URL
|
|
10
|
+
* path, and `CallServer` VERIFIES inside a replay window.
|
|
11
|
+
* outbound the worker dials the chat channel; `id` is the channel name,
|
|
12
|
+
* and `ChatChannel` SIGNS.
|
|
13
|
+
*
|
|
14
|
+
* Chat POSTs sign the exact body bytes with a five-minute replay window.
|
|
15
|
+
* Control requests use v2, binding the method, path and hash of the whole body.
|
|
16
|
+
*
|
|
17
|
+
* Byte-for-byte identical to the Python SDK's `standin/sdk/_hmac.py`; the shared
|
|
18
|
+
* conformance vectors assert that a signature produced by either verifies in the
|
|
19
|
+
* other.
|
|
20
|
+
*/
|
|
21
|
+
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
22
|
+
export const TIMESTAMP_HEADER = "x-standin-timestamp";
|
|
23
|
+
export const SIGNATURE_HEADER = "x-standin-signature";
|
|
24
|
+
export const SIGNATURE_V2_HEADER = "x-standin-signature-v2";
|
|
25
|
+
/** Handshakes are dialed and answered immediately; anything older is a replay. */
|
|
26
|
+
export const REPLAY_WINDOW_MS = 60_000;
|
|
27
|
+
/** Chat POSTs allow delayed relay retries; WebSocket upgrades still use 60 s. */
|
|
28
|
+
export const CHAT_REPLAY_WINDOW_MS = 300_000;
|
|
29
|
+
export function nowMs() {
|
|
30
|
+
return Date.now();
|
|
31
|
+
}
|
|
32
|
+
/** Signature for a WebSocket upgrade. */
|
|
33
|
+
export function signHandshake(secret, timestampMs, handshakeId) {
|
|
34
|
+
return createHmac("sha256", secret)
|
|
35
|
+
.update(`${timestampMs}.${handshakeId}`, "utf8")
|
|
36
|
+
.digest("hex");
|
|
37
|
+
}
|
|
38
|
+
/** Constant-time check of an inbound upgrade. Empty inputs fail CLOSED. */
|
|
39
|
+
export function verifyHandshake(secret, timestamp, handshakeId, signature, currentMs) {
|
|
40
|
+
if (!secret || !timestamp || !signature)
|
|
41
|
+
return false;
|
|
42
|
+
// Restrict the timestamp to ASCII decimal, matching the Python SDK.
|
|
43
|
+
// Number() also accepts empty strings, hexadecimal and exponent notation.
|
|
44
|
+
if (!/^-?\d+$/.test(timestamp.trim()))
|
|
45
|
+
return false;
|
|
46
|
+
const ts = Number(timestamp.trim());
|
|
47
|
+
if (!Number.isFinite(ts))
|
|
48
|
+
return false;
|
|
49
|
+
const now = currentMs ?? nowMs();
|
|
50
|
+
if (Math.abs(now - ts) > REPLAY_WINDOW_MS)
|
|
51
|
+
return false;
|
|
52
|
+
const expected = signHandshake(secret, timestamp, handshakeId);
|
|
53
|
+
const given = signature.trim().toLowerCase();
|
|
54
|
+
// timingSafeEqual THROWS on a length mismatch, and this is reachable by anyone
|
|
55
|
+
// who can open a socket. Unguarded, a short signature header turns an
|
|
56
|
+
// unauthenticated upgrade into a 500 instead of a 401 - a crash path, and an
|
|
57
|
+
// oracle that tells "malformed" apart from "wrong".
|
|
58
|
+
const a = Buffer.from(expected, "utf8");
|
|
59
|
+
const b = Buffer.from(given, "utf8");
|
|
60
|
+
if (a.length !== b.length)
|
|
61
|
+
return false;
|
|
62
|
+
return timingSafeEqual(a, b);
|
|
63
|
+
}
|
|
64
|
+
/** Sign a chat POST's exact transmitted bytes as `{timestampMs}.{rawBody}`.
|
|
65
|
+
* Strings are UTF-8 encoded. Serialize once and send those same bytes.
|
|
66
|
+
*/
|
|
67
|
+
export function signBody(secret, timestampMs, rawBody) {
|
|
68
|
+
return createHmac("sha256", secret)
|
|
69
|
+
.update(`${timestampMs}.`, "utf8")
|
|
70
|
+
.update(rawBody)
|
|
71
|
+
.digest("hex");
|
|
72
|
+
}
|
|
73
|
+
/** Verify a chat POST, allowing 300 s of clock skew by default.
|
|
74
|
+
* Missing or malformed headers fail closed. The WebSocket chat channel still
|
|
75
|
+
* signs the channel name and uses the separate 60 s window.
|
|
76
|
+
*/
|
|
77
|
+
export function verifyBody(secret, timestamp, rawBody, signature, currentMs, windowMs = CHAT_REPLAY_WINDOW_MS) {
|
|
78
|
+
if (!secret || !timestamp || !signature)
|
|
79
|
+
return false;
|
|
80
|
+
if (!/^-?\d+$/.test(timestamp.trim()))
|
|
81
|
+
return false;
|
|
82
|
+
const ts = Number(timestamp.trim());
|
|
83
|
+
if (!Number.isFinite(ts))
|
|
84
|
+
return false;
|
|
85
|
+
if (Math.abs((currentMs ?? nowMs()) - ts) > windowMs)
|
|
86
|
+
return false;
|
|
87
|
+
const expected = Buffer.from(signBody(secret, timestamp, rawBody), "utf8");
|
|
88
|
+
const given = Buffer.from(signature.trim().toLowerCase(), "utf8");
|
|
89
|
+
if (expected.length !== given.length)
|
|
90
|
+
return false;
|
|
91
|
+
return timingSafeEqual(expected, given);
|
|
92
|
+
}
|
|
93
|
+
/** Return `METHOD\npath\nsha256_hex(body)` for a v2 control request.
|
|
94
|
+
* The path is the HTTP request path, without the origin or query string,
|
|
95
|
+
* matching the worker verifier. The body covers every field, including tenantId.
|
|
96
|
+
*/
|
|
97
|
+
export function canonicalRequest(method, path, rawBody) {
|
|
98
|
+
const bodyHash = createHash("sha256").update(rawBody).digest("hex");
|
|
99
|
+
return `${method.toUpperCase()}\n${path}\n${bodyHash}`;
|
|
100
|
+
}
|
|
101
|
+
/** Sign an outbound control request for X-StandIn-Signature-V2.
|
|
102
|
+
* Pass the exact bytes you will transmit. v1 handshakes remain supported for
|
|
103
|
+
* WebSockets; control requests should send this v2 header.
|
|
104
|
+
*/
|
|
105
|
+
export function signRequest(secret, timestampMs, method, path, rawBody) {
|
|
106
|
+
return signHandshake(secret, timestampMs, canonicalRequest(method, path, rawBody));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=hmac.js.map
|
package/dist/hmac.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmac.js","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StandIn SDK - put your AI agent into a Microsoft Teams call.
|
|
3
|
+
*
|
|
4
|
+
* StandIn (https://standin.komaa.com) is the hosted bridge that joins the Microsoft Teams
|
|
5
|
+
* call: it owns the Microsoft side entirely - the bot registration, Graph, media
|
|
6
|
+
* negotiation, the avatar tile - and speaks to your worker over one
|
|
7
|
+
* authenticated socket per call. This package is that socket's other end.
|
|
8
|
+
*
|
|
9
|
+
* The Python SDK (`standin-sdk` on PyPI) is the same API, same seam, same wire
|
|
10
|
+
* protocol. Which one you use is decided by the framework you are integrating,
|
|
11
|
+
* not by preference.
|
|
12
|
+
*
|
|
13
|
+
* This module is the CORE, and it is the whole reason one package works: it
|
|
14
|
+
* imports nothing from `plugins/`, so `import { CallServer } from
|
|
15
|
+
* "@komaa/standin-sdk"` succeeds on a machine with no framework installed at
|
|
16
|
+
* all. A plugin is reached by its own subpath - `@komaa/standin-sdk/echo`,
|
|
17
|
+
* `@komaa/standin-sdk/openclaw` - and only a caller that already has that
|
|
18
|
+
* framework ever loads it. Keep it that way: one framework import at the top of
|
|
19
|
+
* a file reachable from here would break every install that does not use it.
|
|
20
|
+
*
|
|
21
|
+
* You do not normally use this directly. Reach for the plugin for your
|
|
22
|
+
* framework; the root-level examples show a complete deployment of each.
|
|
23
|
+
*
|
|
24
|
+
* Writing a plugin is the other direction, and it is deliberately small -
|
|
25
|
+
* see {@link CallHandler}, or copy `plugins/echo`, which answers a real
|
|
26
|
+
* call in under 100 lines.
|
|
27
|
+
*/
|
|
28
|
+
export { BYTES_PER_SAMPLE, FRAME_BYTES, FRAME_MS, REALTIME_SAMPLE_RATE_HZ, FrameAligner, frameDurationMs, pcm16Rms, resamplePcm16, } from "./audio.js";
|
|
29
|
+
export { EMOTIONS, ExpressionCue, MAX_EMOTION_CHARS, MAX_VISEME_ID, type Emotion, type InferredEmotion, type SpeechMark, expression, inferEmotion, speechMarks, } from "./avatar.js";
|
|
30
|
+
export { MAX_AUDIO_BUFFER_BYTES, CallServer, type CallServerOptions, } from "./callServer.js";
|
|
31
|
+
export { TROUBLE_ANSWERING, TROUBLE_HEARING, TROUBLE_SPEAKING, VoiceLane, type Answer, type Synthesize, type Transcribe, type VoiceLaneOptions, type VoiceTurn, } from "./lane.js";
|
|
32
|
+
export { SyntheticCall, runSmoke, report as smokeReport, type SmokeCheck, type SmokeResult, } from "./smoke.js";
|
|
33
|
+
export { LiveCalls, TENANT_ENV, VoiceDelivery, type Delivery, type LiveSpeaker, type VoiceDeliveryOptions, } from "./delivery.js";
|
|
34
|
+
export { BUILT_IN_TOOLS, SHOW_PAGE_TOOL, CallTools, type CallToolsOptions, type ToolDialect, type ToolHandler, type ToolResult, type ToolSpec, toolSchemas, } from "./callTools.js";
|
|
35
|
+
export { flag, jsonObject, optional, required, vendorHost } from "./config.js";
|
|
36
|
+
export { BACKGROUND_TASK_TOOL, CONSULT_TOOL, DEFAULT_CONSULT_TIMEOUT_MS, DEFAULT_RESUME_LIMIT, DEFAULT_TASK_TIMEOUT_MS, DEFAULT_TASK_TTL_MS, BackgroundTasks, Consultant, type Asker, type AskerFactory, type BackgroundTask, type BackgroundTasksOptions, type Deliverer, } from "./consult.js";
|
|
37
|
+
export { CHAT_FALLBACK_WINDOW_MS, PersonalChats, type PersonalChat, DEFAULT_CHAT_URL, OUTBOUND_IMAGE_CONTENT_TYPES, OUTBOUND_IMAGE_MAX_BYTES, SCHEMA_VERSION, ChatChannel, type ChatChannelOptions, type InboundMessage, type OutboundImage, buildReply, isPersonal, outboundImage, parseInbound, sanitizeImageName, sniffImageType, } from "./chat.js";
|
|
38
|
+
export { ECHO_BARGE_IN_RMS, ECHO_SUPPRESSION_WINDOW_MS, pcm16Rms as echoPcm16Rms, shouldSuppressEcho, type EchoGuardOptions, } from "./echoGuard.js";
|
|
39
|
+
export { StandInError } from "./errors.js";
|
|
40
|
+
export { DEFAULT_FOLLOW_UP_WINDOW_MS, GroupGate, type GateDecision, type GroupGateOptions, isAddressed, isMeetingThread, isVerbalInterrupt, } from "./gate.js";
|
|
41
|
+
export { describeInboundRejection, isAllowlistedCaller, isInboundCallAllowed, normalizePhoneNumber, } from "./policy.js";
|
|
42
|
+
export { type ForbiddenIpFn, type LookupFn, assertPublicHttpUrl, fetchPublicImage, isForbiddenIp, } from "./fetch.js";
|
|
43
|
+
export type { CallHandler, CallSession, HandlerFactory } from "./handler.js";
|
|
44
|
+
export { CHAT_REPLAY_WINDOW_MS, REPLAY_WINDOW_MS, SIGNATURE_HEADER, SIGNATURE_V2_HEADER, TIMESTAMP_HEADER, canonicalRequest, nowMs, signBody, signHandshake, signRequest, verifyBody, verifyHandshake, } from "./hmac.js";
|
|
45
|
+
export { ATTACHMENT_NOTE_MAX_LINES, CARD_PAYLOAD_MAX_CHARS, CLIP_FETCH_ATTEMPTS, CLIP_FETCH_TIMEOUT_MS, IMAGE_FETCH_ATTEMPTS, IMAGE_FETCH_TIMEOUT_MS, MAX_CLIPS, MAX_CLIP_BYTES, MAX_IMAGES, type ChatAudio, type ChatImage, type ChatTurn, type ChatTurnOptions, type FetchOptions, type Transcriber, attachmentsNote, buildChatTurn, cardActionNote, chatAttachmentOrigin, chatImageData, chatImageDataUrl, fetchChatAudio, fetchChatImages, spoolClip, transcribeVoiceMessages, } from "./attachments.js";
|
|
46
|
+
export { AMBIENT_BACKSTOP_MS, AMBIENT_SOURCE_ORDER, DEFAULT_AMBIENT_MAX_PER_MINUTE, MAX_QUEUED_AMBIENT_IMAGES, AmbientVision, type AmbientImage, type AmbientSession, type AmbientSink, type AmbientVisionOptions, ambientImageDataUrl, } from "./ambient.js";
|
|
47
|
+
export { type Logger, setLogger } from "./log.js";
|
|
48
|
+
export { MEDIA_ROOTS_ENV, type AgentMedia, type LoadMediaOptions, loadMedia, mediaRoots, parseMedia, } from "./media.js";
|
|
49
|
+
export { DEFAULT_MAX_UTTERANCE_MS, DEFAULT_MIN_UTTERANCE_MS, DEFAULT_PREROLL_MS, DEFAULT_SILENCE_MS, DEFAULT_SPEECH_RMS, PacedPlayback, UtteranceSegmenter, type FrameSink, type Playback, type SegmenterOptions, decodeWav, encodeWav, } from "./voice.js";
|
|
50
|
+
export { DOCUMENT_NOT_ATTACHED, MAX_TRANSCRIPT_CHARS, MAX_TRANSCRIPT_ENTRIES, MAX_TRANSCRIPT_ENTRY_CHARS, MAX_TRANSCRIPT_TURNS, MAX_TRANSCRIPT_VISUALS, MINUTES_TOOL, RECAP_MIN_TURNS, Transcript, type DeliveryTarget, type MinutesSection, type MinutesTargetOptions, type PostMinutesOptions, type PostOutcome, type Poster, type RecapResult, type Summariser, type TranscriptOptions, type Turn, type TurnRole, hasSpeakerPrefix, isSummaryRequest, minutesPrompt, parseMinutesSections, postMinutes, resolveMinutesTarget, writeMinutesDocx, } from "./minutes.js";
|
|
51
|
+
export { CHAR_VISEMES, SILENCE_VISEME, TurnLipSync, estimateVisemes, visemeForChar, visemesFromAlignment, type TurnLipSyncOptions, } from "./lipsync.js";
|
|
52
|
+
export { OutboundCaller, OutboundError, OutboundPolicy, PendingMessages, type OutboundCallerOptions, type OutboundPolicyOptions, type PendingMessage, type PlacedCall, stateDir, CALL_BACK_TOOL, CHAT_CALLBACK_TOOL, CHAT_CALLBACK_WINDOW_MS, DEFAULT_ANSWER_TIMEOUT_MS, MAX_PENDING_TEXT_CHARS, NO_ANSWER_PREFIX, OUTCOME_WORDING, UNANSWERED_OUTCOMES, OutboundLane, OutboundLeg, type ChatCallbackTarget, type ChatSender, type OutboundLaneOptions, type OutboundSession, type Speak, callThreadIsPostable, } from "./outbound.js";
|
|
53
|
+
export { NUM_CHANNELS, SAMPLE_RATE_HZ, type Caller, type SessionStart, assistantCancel, audioFrame, contextSentences, decodePcm, parseMessage, parseSessionStart, pong, sessionEnd, } from "./protocol.js";
|
|
54
|
+
export { MAX_TILE_FPS, TILE_HEIGHT, TILE_WIDTH, TileStream, type Encoder, type TileStreamOptions, jpegEncoder, } from "./tile.js";
|
|
55
|
+
export { DISPLAY_MODES, KeyframeStore, PAGE_DISPLAY_MS, PAGE_RENDER_TIMEOUT_MS, MAX_SLIDESHOW_IMAGES, SLIDESHOW_HOLD_MS, SLIDESHOW_OVERLAP_MS, ShownImage, VisionBudget, VisionTools, displayImageName, normalizeDisplayMode, type PageRenderer, type ShowItem, type Speaker, type VisionToolsOptions, type WalkthroughStep, } from "./visionTools.js";
|
|
56
|
+
export { MAX_PENDING_AUDIO, MAX_PENDING_CONTEXT, StartupBuffer, } from "./startup.js";
|
|
57
|
+
export { VERSION } from "./version.js";
|
|
58
|
+
export { DISPLAY_IMAGE_MIME_TYPES, MAX_IMAGE_BYTES, VIDEO_SOURCES, FrameDescriber, type FrameDescriberOptions, type DisplayFrameOptions, type DisplayImageMime, type DisplayImageMode, type DisplayImageOptions, type VideoFrame, type VideoSource, displayFrame, displayImage, parseVideoFrame, fallbackOwner, frameCaption, frameDigest, frameOwner, } from "./vision.js";
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright (c) 2026 Komaa DigiTech
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* StandIn SDK - put your AI agent into a Microsoft Teams call.
|
|
5
|
+
*
|
|
6
|
+
* StandIn (https://standin.komaa.com) is the hosted bridge that joins the Microsoft Teams
|
|
7
|
+
* call: it owns the Microsoft side entirely - the bot registration, Graph, media
|
|
8
|
+
* negotiation, the avatar tile - and speaks to your worker over one
|
|
9
|
+
* authenticated socket per call. This package is that socket's other end.
|
|
10
|
+
*
|
|
11
|
+
* The Python SDK (`standin-sdk` on PyPI) is the same API, same seam, same wire
|
|
12
|
+
* protocol. Which one you use is decided by the framework you are integrating,
|
|
13
|
+
* not by preference.
|
|
14
|
+
*
|
|
15
|
+
* This module is the CORE, and it is the whole reason one package works: it
|
|
16
|
+
* imports nothing from `plugins/`, so `import { CallServer } from
|
|
17
|
+
* "@komaa/standin-sdk"` succeeds on a machine with no framework installed at
|
|
18
|
+
* all. A plugin is reached by its own subpath - `@komaa/standin-sdk/echo`,
|
|
19
|
+
* `@komaa/standin-sdk/openclaw` - and only a caller that already has that
|
|
20
|
+
* framework ever loads it. Keep it that way: one framework import at the top of
|
|
21
|
+
* a file reachable from here would break every install that does not use it.
|
|
22
|
+
*
|
|
23
|
+
* You do not normally use this directly. Reach for the plugin for your
|
|
24
|
+
* framework; the root-level examples show a complete deployment of each.
|
|
25
|
+
*
|
|
26
|
+
* Writing a plugin is the other direction, and it is deliberately small -
|
|
27
|
+
* see {@link CallHandler}, or copy `plugins/echo`, which answers a real
|
|
28
|
+
* call in under 100 lines.
|
|
29
|
+
*/
|
|
30
|
+
export { BYTES_PER_SAMPLE, FRAME_BYTES, FRAME_MS, REALTIME_SAMPLE_RATE_HZ, FrameAligner, frameDurationMs, pcm16Rms, resamplePcm16, } from "./audio.js";
|
|
31
|
+
export { EMOTIONS, ExpressionCue, MAX_EMOTION_CHARS, MAX_VISEME_ID, expression, inferEmotion, speechMarks, } from "./avatar.js";
|
|
32
|
+
export { MAX_AUDIO_BUFFER_BYTES, CallServer, } from "./callServer.js";
|
|
33
|
+
export { TROUBLE_ANSWERING, TROUBLE_HEARING, TROUBLE_SPEAKING, VoiceLane, } from "./lane.js";
|
|
34
|
+
export { SyntheticCall, runSmoke, report as smokeReport, } from "./smoke.js";
|
|
35
|
+
export { LiveCalls, TENANT_ENV, VoiceDelivery, } from "./delivery.js";
|
|
36
|
+
export { BUILT_IN_TOOLS, SHOW_PAGE_TOOL, CallTools, toolSchemas, } from "./callTools.js";
|
|
37
|
+
export { flag, jsonObject, optional, required, vendorHost } from "./config.js";
|
|
38
|
+
export { BACKGROUND_TASK_TOOL, CONSULT_TOOL, DEFAULT_CONSULT_TIMEOUT_MS, DEFAULT_RESUME_LIMIT, DEFAULT_TASK_TIMEOUT_MS, DEFAULT_TASK_TTL_MS, BackgroundTasks, Consultant, } from "./consult.js";
|
|
39
|
+
export { CHAT_FALLBACK_WINDOW_MS, PersonalChats, DEFAULT_CHAT_URL, OUTBOUND_IMAGE_CONTENT_TYPES, OUTBOUND_IMAGE_MAX_BYTES, SCHEMA_VERSION, ChatChannel, buildReply, isPersonal, outboundImage, parseInbound, sanitizeImageName, sniffImageType, } from "./chat.js";
|
|
40
|
+
export { ECHO_BARGE_IN_RMS, ECHO_SUPPRESSION_WINDOW_MS, pcm16Rms as echoPcm16Rms, shouldSuppressEcho, } from "./echoGuard.js";
|
|
41
|
+
export { StandInError } from "./errors.js";
|
|
42
|
+
export { DEFAULT_FOLLOW_UP_WINDOW_MS, GroupGate, isAddressed, isMeetingThread, isVerbalInterrupt, } from "./gate.js";
|
|
43
|
+
export { describeInboundRejection, isAllowlistedCaller, isInboundCallAllowed, normalizePhoneNumber, } from "./policy.js";
|
|
44
|
+
export { assertPublicHttpUrl, fetchPublicImage, isForbiddenIp, } from "./fetch.js";
|
|
45
|
+
export { CHAT_REPLAY_WINDOW_MS, REPLAY_WINDOW_MS, SIGNATURE_HEADER, SIGNATURE_V2_HEADER, TIMESTAMP_HEADER, canonicalRequest, nowMs, signBody, signHandshake, signRequest, verifyBody, verifyHandshake, } from "./hmac.js";
|
|
46
|
+
export { ATTACHMENT_NOTE_MAX_LINES, CARD_PAYLOAD_MAX_CHARS, CLIP_FETCH_ATTEMPTS, CLIP_FETCH_TIMEOUT_MS, IMAGE_FETCH_ATTEMPTS, IMAGE_FETCH_TIMEOUT_MS, MAX_CLIPS, MAX_CLIP_BYTES, MAX_IMAGES, attachmentsNote, buildChatTurn, cardActionNote, chatAttachmentOrigin, chatImageData, chatImageDataUrl, fetchChatAudio, fetchChatImages, spoolClip, transcribeVoiceMessages, } from "./attachments.js";
|
|
47
|
+
export { AMBIENT_BACKSTOP_MS, AMBIENT_SOURCE_ORDER, DEFAULT_AMBIENT_MAX_PER_MINUTE, MAX_QUEUED_AMBIENT_IMAGES, AmbientVision, ambientImageDataUrl, } from "./ambient.js";
|
|
48
|
+
export { setLogger } from "./log.js";
|
|
49
|
+
export { MEDIA_ROOTS_ENV, loadMedia, mediaRoots, parseMedia, } from "./media.js";
|
|
50
|
+
export { DEFAULT_MAX_UTTERANCE_MS, DEFAULT_MIN_UTTERANCE_MS, DEFAULT_PREROLL_MS, DEFAULT_SILENCE_MS, DEFAULT_SPEECH_RMS, PacedPlayback, UtteranceSegmenter, decodeWav, encodeWav, } from "./voice.js";
|
|
51
|
+
export { DOCUMENT_NOT_ATTACHED, MAX_TRANSCRIPT_CHARS, MAX_TRANSCRIPT_ENTRIES, MAX_TRANSCRIPT_ENTRY_CHARS, MAX_TRANSCRIPT_TURNS, MAX_TRANSCRIPT_VISUALS, MINUTES_TOOL, RECAP_MIN_TURNS, Transcript, hasSpeakerPrefix, isSummaryRequest, minutesPrompt, parseMinutesSections, postMinutes, resolveMinutesTarget, writeMinutesDocx, } from "./minutes.js";
|
|
52
|
+
export { CHAR_VISEMES, SILENCE_VISEME, TurnLipSync, estimateVisemes, visemeForChar, visemesFromAlignment, } from "./lipsync.js";
|
|
53
|
+
export { OutboundCaller, OutboundError, OutboundPolicy, PendingMessages, stateDir, CALL_BACK_TOOL, CHAT_CALLBACK_TOOL, CHAT_CALLBACK_WINDOW_MS, DEFAULT_ANSWER_TIMEOUT_MS, MAX_PENDING_TEXT_CHARS, NO_ANSWER_PREFIX, OUTCOME_WORDING, UNANSWERED_OUTCOMES, OutboundLane, OutboundLeg, callThreadIsPostable, } from "./outbound.js";
|
|
54
|
+
export { NUM_CHANNELS, SAMPLE_RATE_HZ, assistantCancel, audioFrame, contextSentences, decodePcm, parseMessage, parseSessionStart, pong, sessionEnd, } from "./protocol.js";
|
|
55
|
+
export { MAX_TILE_FPS, TILE_HEIGHT, TILE_WIDTH, TileStream, jpegEncoder, } from "./tile.js";
|
|
56
|
+
export { DISPLAY_MODES, KeyframeStore, PAGE_DISPLAY_MS, PAGE_RENDER_TIMEOUT_MS, MAX_SLIDESHOW_IMAGES, SLIDESHOW_HOLD_MS, SLIDESHOW_OVERLAP_MS, ShownImage, VisionBudget, VisionTools, displayImageName, normalizeDisplayMode, } from "./visionTools.js";
|
|
57
|
+
export { MAX_PENDING_AUDIO, MAX_PENDING_CONTEXT, StartupBuffer, } from "./startup.js";
|
|
58
|
+
export { VERSION } from "./version.js";
|
|
59
|
+
export { DISPLAY_IMAGE_MIME_TYPES, MAX_IMAGE_BYTES, VIDEO_SOURCES, FrameDescriber, displayFrame, displayImage, parseVideoFrame, fallbackOwner, frameCaption, frameDigest, frameOwner, } from "./vision.js";
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,+BAA+B;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,uBAAuB,EACvB,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,aAAa,EAIb,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,UAAU,GAEX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,SAAS,GAMV,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,QAAQ,EACR,MAAM,IAAI,WAAW,GAGtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,UAAU,EACV,aAAa,GAId,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,cAAc,EACd,SAAS,EAMT,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,UAAU,GAMX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,uBAAuB,EACvB,aAAa,EAEb,gBAAgB,EAChB,4BAA4B,EAC5B,wBAAwB,EACxB,cAAc,EACd,WAAW,EAIX,UAAU,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,QAAQ,IAAI,YAAY,EACxB,kBAAkB,GAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,2BAA2B,EAC3B,SAAS,EAGT,WAAW,EACX,eAAe,EACf,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACL,QAAQ,EACR,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,SAAS,EACT,cAAc,EACd,UAAU,EAOV,eAAe,EACf,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,SAAS,EACT,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,8BAA8B,EAC9B,yBAAyB,EACzB,aAAa,EAKb,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAe,SAAS,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EACL,eAAe,EAGf,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAIlB,SAAS,EACT,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,eAAe,EACf,UAAU,EAYV,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,EACb,oBAAoB,GAErB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EAKf,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,WAAW,EAMX,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,cAAc,EAGd,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,IAAI,EACJ,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EAGV,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,oBAAoB,GAMrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,aAAa,EACb,cAAc,EAQd,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EACb,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,aAAa,CAAC"}
|