@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Komaa DigiTech
|
|
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,141 @@
|
|
|
1
|
+
# @komaa/standin-sdk
|
|
2
|
+
|
|
3
|
+
[StandIn](https://standin.komaa.com) for TypeScript: the SDK core and every
|
|
4
|
+
framework plugin, in one package.
|
|
5
|
+
|
|
6
|
+
StandIn is the hosted bridge that joins a Microsoft Teams call. It owns the
|
|
7
|
+
Microsoft side entirely, the bot registration, Graph, media negotiation, the
|
|
8
|
+
avatar tile, and talks to your worker over one authenticated socket per call.
|
|
9
|
+
This package is that socket's other end.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @komaa/standin-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Node 20 or newer. Nothing else is required to answer a call.
|
|
18
|
+
|
|
19
|
+
## One package, every entry point
|
|
20
|
+
|
|
21
|
+
| Import | What it is | Needs installed |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `@komaa/standin-sdk` | The core: `CallServer`, `CallHandler`, `ChatChannel`, the audio and HMAC helpers | nothing but `ws` |
|
|
24
|
+
| `@komaa/standin-sdk/echo` | The smallest plugin that answers a real call. Copy it to start your own | nothing but `ws` |
|
|
25
|
+
| `@komaa/standin-sdk/elevenlabs` | An ElevenLabs agent takes the call | nothing but `ws` |
|
|
26
|
+
| `@komaa/standin-sdk/deepgram` | A Deepgram Voice Agent takes the call | nothing but `ws` |
|
|
27
|
+
| `@komaa/standin-sdk/cartesia` | A Cartesia Line agent takes the call | nothing but `ws` |
|
|
28
|
+
| `@komaa/standin-sdk/openai` | An OpenAI Realtime model takes the call | nothing but `ws` |
|
|
29
|
+
| `@komaa/standin-sdk/livekit` | A LiveKit agent takes the call | `@livekit/rtc-node`, `livekit-server-sdk` |
|
|
30
|
+
| `@komaa/standin-sdk/openclaw` | The OpenClaw gateway plugin | `openclaw` |
|
|
31
|
+
|
|
32
|
+
The core imports **nothing** from `src/plugins/`, so installing this package
|
|
33
|
+
never drags a framework in behind you, and `import { CallServer } from
|
|
34
|
+
"@komaa/standin-sdk"` works on a machine with no OpenClaw at all. `openclaw` is
|
|
35
|
+
an optional peer dependency: you install it because you run a gateway, not
|
|
36
|
+
because you installed this.
|
|
37
|
+
|
|
38
|
+
One package is what keeps the plugins honest with each other. A new
|
|
39
|
+
capability lands in the core once and every plugin has it, instead of being
|
|
40
|
+
threaded into one package per framework by hand.
|
|
41
|
+
|
|
42
|
+
## Run the echo agent
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install @komaa/standin-sdk
|
|
46
|
+
STANDIN_SECRET=... npx standin-echo
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Call your StandIn number and talk. You should hear yourself. Run this before you
|
|
50
|
+
suspect your own agent: if the echo answers, your secret, your tunnel and your
|
|
51
|
+
StandIn identity are all correct.
|
|
52
|
+
|
|
53
|
+
From there, the [OpenClaw example](../../examples/openclaw-msteams-connector) is a
|
|
54
|
+
complete deployment, and the [echo plugin](src/plugins/echo) is the
|
|
55
|
+
file to copy for a custom one.
|
|
56
|
+
|
|
57
|
+
The [Python SDK](../python) uses the same call handler contract and wire
|
|
58
|
+
protocol. Shared conformance vectors check the behaviour of both SDKs. The
|
|
59
|
+
framework plugins are OpenClaw in TypeScript, Hermes in Python, and LiveKit
|
|
60
|
+
in both.
|
|
61
|
+
|
|
62
|
+
## What it gives you
|
|
63
|
+
|
|
64
|
+
| | |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `CallServer` | Answers the socket StandIn dials. Owns the HMAC handshake and its replay guard, capacity and draining, the wire protocol, sequence numbers and the audio timeline, and the watchdogs that end a call nobody closed. |
|
|
67
|
+
| `CallHandler` | The five-method seam a plugin implements. Every method optional. |
|
|
68
|
+
| `VideoFrame` | One frame of what the caller is showing, on the vision lane. |
|
|
69
|
+
|
|
70
|
+
## Writing a plugin
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { CallServer, type CallSession } from "@komaa/standin-sdk";
|
|
74
|
+
|
|
75
|
+
class EchoHandler {
|
|
76
|
+
#call!: CallSession;
|
|
77
|
+
|
|
78
|
+
async onStart(session: CallSession) {
|
|
79
|
+
this.#call = session;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async onCallerAudio(pcm: Buffer) {
|
|
83
|
+
await this.#call.sendAudio(pcm); // PCM16, 16 kHz, mono
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const server = new CallServer({ handlerFactory: () => new EchoHandler() });
|
|
88
|
+
await server.start();
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
That is a working Microsoft Teams agent. `@komaa/standin-sdk/echo` is this file plus a
|
|
92
|
+
signal handler, and `npx standin-echo` runs it.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
Environment only.
|
|
97
|
+
|
|
98
|
+
| Variable | Default | Meaning |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `STANDIN_SECRET` | *(required)* | Connection secret from the StandIn portal. |
|
|
101
|
+
| `STANDIN_PORT` | `9442` | Port the call listener binds. |
|
|
102
|
+
| `STANDIN_HOST` | `0.0.0.0` | Bind address. Use `127.0.0.1` when only a local tunnel should reach it. |
|
|
103
|
+
| `STANDIN_WS_PATH` | `/msteams/calling` | Path StandIn dials. |
|
|
104
|
+
|
|
105
|
+
The listener authenticates WebSocket upgrades with HMAC. Terminate TLS at your
|
|
106
|
+
public ingress so StandIn can reach it over `wss://`.
|
|
107
|
+
|
|
108
|
+
## Signing control requests
|
|
109
|
+
|
|
110
|
+
Use `signRequest` for HTTP control requests. HMAC v2 binds the method, request
|
|
111
|
+
path and hash of the entire body, including `tenantId`:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { SIGNATURE_V2_HEADER, TIMESTAMP_HEADER, nowMs, signRequest } from "@komaa/standin-sdk";
|
|
115
|
+
|
|
116
|
+
const timestamp = String(nowMs());
|
|
117
|
+
const headers = {
|
|
118
|
+
[TIMESTAMP_HEADER]: timestamp,
|
|
119
|
+
[SIGNATURE_V2_HEADER]: signRequest(secret, timestamp, "POST", "/api/calls", rawBody),
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Serialize the body once and send those same `rawBody` bytes. These helpers
|
|
124
|
+
prepare signatures; they do not send HTTP requests. `signBody` / `verifyBody`
|
|
125
|
+
are for chat POST bodies, with a 300-second replay window. WebSocket call and
|
|
126
|
+
chat-channel handshakes keep `signHandshake` / `verifyHandshake` and their
|
|
127
|
+
separate 60-second window.
|
|
128
|
+
|
|
129
|
+
## Audio
|
|
130
|
+
|
|
131
|
+
PCM16, 16 kHz, mono, little-endian, both directions. The server owns the
|
|
132
|
+
outbound sequence number and timeline, so a handler that swaps or re-publishes
|
|
133
|
+
its audio source cannot make timestamps jump backwards.
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
Building the package from a clone, the layout rules for a new plugin and
|
|
138
|
+
the checks CI runs are in
|
|
139
|
+
[CONTRIBUTING.md](https://github.com/komaa-com/standin/blob/main/CONTRIBUTING.md).
|
|
140
|
+
|
|
141
|
+
[MIT](LICENSE).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type VideoFrame } from "./vision.js";
|
|
2
|
+
import { VisionBudget } from "./visionTools.js";
|
|
3
|
+
/**
|
|
4
|
+
* How often to look again even when no frame arrived. A screen share can go
|
|
5
|
+
* quiet without ending, and the last thing on it is still what is being
|
|
6
|
+
* discussed.
|
|
7
|
+
*/
|
|
8
|
+
export declare const AMBIENT_BACKSTOP_MS = 6000;
|
|
9
|
+
/**
|
|
10
|
+
* Images held while the provider's socket is not up yet. Bounded: a sink that
|
|
11
|
+
* never comes up would otherwise hold the whole call's video.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAX_QUEUED_AMBIENT_IMAGES = 6;
|
|
14
|
+
/**
|
|
15
|
+
* Screen share first. Somebody presenting is nearly always talking about the
|
|
16
|
+
* screen rather than about their face.
|
|
17
|
+
*/
|
|
18
|
+
export declare const AMBIENT_SOURCE_ORDER: readonly ["screenshare", "camera"];
|
|
19
|
+
/** The default ceiling when a plugin gives no budget of its own. */
|
|
20
|
+
export declare const DEFAULT_AMBIENT_MAX_PER_MINUTE = 30;
|
|
21
|
+
/** One frame, ready to hand to a provider, with who it came from. */
|
|
22
|
+
export interface AmbientImage {
|
|
23
|
+
readonly source: string;
|
|
24
|
+
readonly mime: string;
|
|
25
|
+
readonly dataBase64: string;
|
|
26
|
+
readonly width: number;
|
|
27
|
+
readonly height: number;
|
|
28
|
+
readonly ts: number;
|
|
29
|
+
/** Who is showing it. Degrades to "the caller" rather than vanishing. */
|
|
30
|
+
readonly owner: string;
|
|
31
|
+
/** A sentence to put beside the image, so the model knows whose screen it is. */
|
|
32
|
+
readonly caption: string;
|
|
33
|
+
}
|
|
34
|
+
/** The `data:` form most vision APIs take directly. */
|
|
35
|
+
export declare function ambientImageDataUrl(image: AmbientImage): string;
|
|
36
|
+
/**
|
|
37
|
+
* Hand one image to the provider.
|
|
38
|
+
*
|
|
39
|
+
* It MUST NOT make the agent reply: ambient vision is context, and an agent that
|
|
40
|
+
* answers every scene change talks over the person presenting. It MUST reject on
|
|
41
|
+
* failure, because a silent failure latches a frame that never arrived and the
|
|
42
|
+
* model never sees that screen again.
|
|
43
|
+
*/
|
|
44
|
+
export type AmbientSink = (image: AmbientImage) => Promise<void>;
|
|
45
|
+
/** What a session has to offer for ambient vision to gate on it. */
|
|
46
|
+
export interface AmbientSession {
|
|
47
|
+
readonly recordingActive: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** Options for {@link AmbientVision}. */
|
|
50
|
+
export interface AmbientVisionOptions {
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
budget?: VisionBudget;
|
|
53
|
+
requireRecording?: boolean;
|
|
54
|
+
sinkReady?: () => boolean;
|
|
55
|
+
changeKey?: (frame: VideoFrame) => string;
|
|
56
|
+
onDelivered?: (image: AmbientImage) => void;
|
|
57
|
+
backstopMs?: number;
|
|
58
|
+
queueMax?: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Push what changed on screen into the conversation, between turns.
|
|
62
|
+
*
|
|
63
|
+
* Built by a plugin that knows how to deliver an image without forcing a reply.
|
|
64
|
+
* {@link offer} is synchronous and never blocks: it runs on the receive path of
|
|
65
|
+
* a live call, and the vision work happens off it.
|
|
66
|
+
*/
|
|
67
|
+
export declare class AmbientVision {
|
|
68
|
+
#private;
|
|
69
|
+
constructor(session: AmbientSession, deliver: AmbientSink, options?: AmbientVisionOptions);
|
|
70
|
+
/** Images held because the provider was not ready for them. */
|
|
71
|
+
get queued(): number;
|
|
72
|
+
get delivered(): number;
|
|
73
|
+
/** Take one frame. Synchronous, non-blocking, and never throws. */
|
|
74
|
+
offer(frame: VideoFrame): void;
|
|
75
|
+
/** Look now. Idempotent, and safe to call from anywhere. */
|
|
76
|
+
flush(): void;
|
|
77
|
+
/** Stop, and stay stopped. */
|
|
78
|
+
close(): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=ambient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ambient.d.ts","sourceRoot":"","sources":["../src/ambient.ts"],"names":[],"mappings":"AAoCA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,oBAAoB,oCAAqC,CAAC;AAEvE,oEAAoE;AACpE,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE/D;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjE,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC;AAED,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,aAAa;;gBAuBtB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,oBAAyB;IA8BpC,+DAA+D;IAC/D,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,mEAAmE;IACnE,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAa9B,4DAA4D;IAC5D,KAAK,IAAI,IAAI;IAeb,8BAA8B;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAqI7B"}
|
package/dist/ambient.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Copyright (c) 2026 Komaa DigiTech
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* Showing the model what the caller is showing, without being asked.
|
|
5
|
+
*
|
|
6
|
+
* `VisionTools` answers when a model reaches for `look`. That is the right shape
|
|
7
|
+
* most of the time, and it has a blind spot: the model has to know there is
|
|
8
|
+
* something to look at. Somebody who shares a deck and says "what do you think?"
|
|
9
|
+
* has told it nothing it can act on.
|
|
10
|
+
*
|
|
11
|
+
* Ambient vision closes that by pushing what changed on screen into the
|
|
12
|
+
* conversation between turns. It is OFF unless a plugin turns it on, because it
|
|
13
|
+
* spends money on every scene change and not every deployment wants that.
|
|
14
|
+
*
|
|
15
|
+
* Three things keep it from being expensive or creepy:
|
|
16
|
+
*
|
|
17
|
+
* **A recording gate**, checked before a frame is even stored. Sending
|
|
18
|
+
* somebody's screen to a model continuously is a different promise from
|
|
19
|
+
* glancing at it once, and the recording is what told them their call is being
|
|
20
|
+
* kept.
|
|
21
|
+
*
|
|
22
|
+
* **Change detection**, so a screen nobody touched costs nothing. The latch is
|
|
23
|
+
* the digest of the last frame actually DELIVERED for that source, not the last
|
|
24
|
+
* one seen: a delivery that failed has to be retried, not skipped.
|
|
25
|
+
*
|
|
26
|
+
* **A reserve**, so the ambient lane cannot spend the whole budget and leave the
|
|
27
|
+
* caller's own "look at this" with nothing left.
|
|
28
|
+
*
|
|
29
|
+
* What to DO with an image stays in the plugin, because only it knows how to
|
|
30
|
+
* hand one to its provider without forcing a reply.
|
|
31
|
+
*
|
|
32
|
+
* Identical in shape to the Python SDK's `standin.ambient`.
|
|
33
|
+
*/
|
|
34
|
+
import { logger } from "./log.js";
|
|
35
|
+
import { fallbackOwner, frameCaption, frameDigest, frameOwner, } from "./vision.js";
|
|
36
|
+
import { VisionBudget } from "./visionTools.js";
|
|
37
|
+
/**
|
|
38
|
+
* How often to look again even when no frame arrived. A screen share can go
|
|
39
|
+
* quiet without ending, and the last thing on it is still what is being
|
|
40
|
+
* discussed.
|
|
41
|
+
*/
|
|
42
|
+
export const AMBIENT_BACKSTOP_MS = 6_000;
|
|
43
|
+
/**
|
|
44
|
+
* Images held while the provider's socket is not up yet. Bounded: a sink that
|
|
45
|
+
* never comes up would otherwise hold the whole call's video.
|
|
46
|
+
*/
|
|
47
|
+
export const MAX_QUEUED_AMBIENT_IMAGES = 6;
|
|
48
|
+
/**
|
|
49
|
+
* Screen share first. Somebody presenting is nearly always talking about the
|
|
50
|
+
* screen rather than about their face.
|
|
51
|
+
*/
|
|
52
|
+
export const AMBIENT_SOURCE_ORDER = ["screenshare", "camera"];
|
|
53
|
+
/** The default ceiling when a plugin gives no budget of its own. */
|
|
54
|
+
export const DEFAULT_AMBIENT_MAX_PER_MINUTE = 30;
|
|
55
|
+
/** The `data:` form most vision APIs take directly. */
|
|
56
|
+
export function ambientImageDataUrl(image) {
|
|
57
|
+
return `data:${image.mime};base64,${image.dataBase64}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Push what changed on screen into the conversation, between turns.
|
|
61
|
+
*
|
|
62
|
+
* Built by a plugin that knows how to deliver an image without forcing a reply.
|
|
63
|
+
* {@link offer} is synchronous and never blocks: it runs on the receive path of
|
|
64
|
+
* a live call, and the vision work happens off it.
|
|
65
|
+
*/
|
|
66
|
+
export class AmbientVision {
|
|
67
|
+
#session;
|
|
68
|
+
#deliver;
|
|
69
|
+
#enabled;
|
|
70
|
+
#requireRecording;
|
|
71
|
+
#sinkReady;
|
|
72
|
+
#changeKey;
|
|
73
|
+
#onDelivered;
|
|
74
|
+
#backstopMs;
|
|
75
|
+
#queueMax;
|
|
76
|
+
#budget;
|
|
77
|
+
#latest = new Map();
|
|
78
|
+
#latched = new Map();
|
|
79
|
+
#queue = [];
|
|
80
|
+
#flushing = false;
|
|
81
|
+
#dirty = false;
|
|
82
|
+
#released = false;
|
|
83
|
+
#delivered = 0;
|
|
84
|
+
#saidHolding = false;
|
|
85
|
+
#backstop;
|
|
86
|
+
constructor(session, deliver, options = {}) {
|
|
87
|
+
this.#session = session;
|
|
88
|
+
this.#deliver = deliver;
|
|
89
|
+
this.#enabled = options.enabled ?? false;
|
|
90
|
+
this.#requireRecording = options.requireRecording ?? true;
|
|
91
|
+
this.#sinkReady = options.sinkReady;
|
|
92
|
+
this.#changeKey =
|
|
93
|
+
options.changeKey ?? ((frame) => frameDigest(frame.dataBase64));
|
|
94
|
+
this.#onDelivered = options.onDelivered;
|
|
95
|
+
this.#backstopMs = Math.max(500, options.backstopMs ?? AMBIENT_BACKSTOP_MS);
|
|
96
|
+
this.#queueMax = Math.max(1, options.queueMax ?? MAX_QUEUED_AMBIENT_IMAGES);
|
|
97
|
+
if (options.budget === undefined) {
|
|
98
|
+
this.#budget = new VisionBudget(DEFAULT_AMBIENT_MAX_PER_MINUTE);
|
|
99
|
+
logger.debug("standin: ambient vision has its own budget, so ambient and explicit looks " +
|
|
100
|
+
"are capped separately");
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.#budget = options.budget;
|
|
104
|
+
if (this.#enabled && options.budget.maxPerMinute === 0) {
|
|
105
|
+
logger.warn("standin: ambient vision is on with an uncapped budget; every scene change " +
|
|
106
|
+
"will be charged. Set maxPerMinute, or leave enabled off.");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Images held because the provider was not ready for them. */
|
|
111
|
+
get queued() {
|
|
112
|
+
return this.#queue.length;
|
|
113
|
+
}
|
|
114
|
+
get delivered() {
|
|
115
|
+
return this.#delivered;
|
|
116
|
+
}
|
|
117
|
+
/** Take one frame. Synchronous, non-blocking, and never throws. */
|
|
118
|
+
offer(frame) {
|
|
119
|
+
if (!this.#enabled || this.#released)
|
|
120
|
+
return;
|
|
121
|
+
if (this.#requireRecording && !this.#session.recordingActive) {
|
|
122
|
+
// Gated before it is STORED, not just before it is sent. Keeping a frame
|
|
123
|
+
// captured while the gate was shut would let opening the gate surface
|
|
124
|
+
// something from before the caller was told.
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.#latest.set(frame.source, frame);
|
|
128
|
+
this.#armBackstop();
|
|
129
|
+
this.flush();
|
|
130
|
+
}
|
|
131
|
+
/** Look now. Idempotent, and safe to call from anywhere. */
|
|
132
|
+
flush() {
|
|
133
|
+
if (!this.#enabled || this.#released)
|
|
134
|
+
return;
|
|
135
|
+
if (this.#flushing) {
|
|
136
|
+
// One more pass after this one, rather than two at once.
|
|
137
|
+
this.#dirty = true;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.#flushing = true;
|
|
141
|
+
// Scheduled, not started here. Calling an async function runs its body up to
|
|
142
|
+
// the first await SYNCHRONOUSLY, so a pass begun inside offer() would see
|
|
143
|
+
// only the frames offered so far and deliver them out of order. It would
|
|
144
|
+
// also do vision work on the receive path, which offer() promises not to.
|
|
145
|
+
void Promise.resolve().then(() => this.#run());
|
|
146
|
+
}
|
|
147
|
+
/** Stop, and stay stopped. */
|
|
148
|
+
async close() {
|
|
149
|
+
this.#released = true;
|
|
150
|
+
this.#latest.clear();
|
|
151
|
+
this.#latched.clear();
|
|
152
|
+
this.#queue = [];
|
|
153
|
+
clearInterval(this.#backstop);
|
|
154
|
+
this.#backstop = undefined;
|
|
155
|
+
}
|
|
156
|
+
async #run() {
|
|
157
|
+
try {
|
|
158
|
+
for (;;) {
|
|
159
|
+
await this.#pass();
|
|
160
|
+
if (!this.#dirty || this.#released)
|
|
161
|
+
return;
|
|
162
|
+
this.#dirty = false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
logger.error(`standin: the ambient vision pass failed: ${String(err)}`);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
this.#flushing = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async #pass() {
|
|
173
|
+
if (this.#released)
|
|
174
|
+
return;
|
|
175
|
+
const ready = this.#sinkReady === undefined || this.#sinkReady();
|
|
176
|
+
if (ready && this.#queue.length > 0) {
|
|
177
|
+
// What was held goes first, oldest first: the model should see the screen
|
|
178
|
+
// change in the order it happened.
|
|
179
|
+
await this.#drain();
|
|
180
|
+
}
|
|
181
|
+
for (const source of AMBIENT_SOURCE_ORDER) {
|
|
182
|
+
if (this.#released)
|
|
183
|
+
return;
|
|
184
|
+
const frame = this.#latest.get(source);
|
|
185
|
+
if (frame === undefined)
|
|
186
|
+
continue;
|
|
187
|
+
const key = this.#changeKey(frame);
|
|
188
|
+
// Nothing changed. A frozen screen costs nothing.
|
|
189
|
+
if (this.#latched.get(source) === key)
|
|
190
|
+
continue;
|
|
191
|
+
const token = this.#budget.tryConsumeAmbient();
|
|
192
|
+
// Out of the ambient allowance. Stop the pass rather than trying the next
|
|
193
|
+
// source, which would spend the same exhausted budget.
|
|
194
|
+
if (token === undefined)
|
|
195
|
+
return;
|
|
196
|
+
const image = this.#image(frame);
|
|
197
|
+
if (!ready) {
|
|
198
|
+
// Charged and latched: it is going to be sent, just not yet. Refunding
|
|
199
|
+
// here would re-send the same screen when the sink comes up.
|
|
200
|
+
this.#latched.set(source, key);
|
|
201
|
+
this.#hold(image);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
await this.#deliver(image);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
// The latch is untouched, so the same screen is tried again.
|
|
209
|
+
this.#budget.refund(token);
|
|
210
|
+
logger.debug(`standin: an ambient frame did not reach the model: ${String(err)}`);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (this.#released)
|
|
214
|
+
return;
|
|
215
|
+
this.#latched.set(source, key);
|
|
216
|
+
this.#delivered += 1;
|
|
217
|
+
this.#note(image);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async #drain() {
|
|
221
|
+
const held = this.#queue;
|
|
222
|
+
this.#queue = [];
|
|
223
|
+
for (const image of held) {
|
|
224
|
+
if (this.#released)
|
|
225
|
+
return;
|
|
226
|
+
try {
|
|
227
|
+
await this.#deliver(image);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
// Already charged and already latched. Dropped rather than re-queued,
|
|
231
|
+
// or a dead sink grows the queue for ever.
|
|
232
|
+
logger.debug(`standin: a held ambient frame was dropped: ${String(err)}`);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
this.#delivered += 1;
|
|
236
|
+
this.#note(image);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
#note(image) {
|
|
240
|
+
if (this.#onDelivered === undefined)
|
|
241
|
+
return;
|
|
242
|
+
try {
|
|
243
|
+
this.#onDelivered(image);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// A bookkeeping hook must not fail a delivery that already happened.
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
#hold(image) {
|
|
250
|
+
if (!this.#saidHolding) {
|
|
251
|
+
logger.info("standin: holding ambient frames until the provider is ready");
|
|
252
|
+
this.#saidHolding = true;
|
|
253
|
+
}
|
|
254
|
+
this.#queue.push(image);
|
|
255
|
+
// Oldest out: what is on screen NOW is worth more than what was.
|
|
256
|
+
if (this.#queue.length > this.#queueMax) {
|
|
257
|
+
this.#queue = this.#queue.slice(-this.#queueMax);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
#image(frame) {
|
|
261
|
+
const owner = frameOwner(frame) ?? fallbackOwner(frame.source);
|
|
262
|
+
return {
|
|
263
|
+
source: frame.source,
|
|
264
|
+
mime: frame.mime,
|
|
265
|
+
dataBase64: frame.dataBase64,
|
|
266
|
+
width: frame.width,
|
|
267
|
+
height: frame.height,
|
|
268
|
+
ts: frame.ts,
|
|
269
|
+
owner,
|
|
270
|
+
caption: frameCaption(owner),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/** Armed on the first accepted frame, so a call with no video has no timer. */
|
|
274
|
+
#armBackstop() {
|
|
275
|
+
if (this.#backstop !== undefined || this.#released)
|
|
276
|
+
return;
|
|
277
|
+
this.#backstop = setInterval(() => this.flush(), this.#backstopMs);
|
|
278
|
+
this.#backstop.unref?.();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=ambient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ambient.js","sourceRoot":"","sources":["../src/ambient.ts"],"names":[],"mappings":"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"}
|