@voxevolv/client 0.1.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,42 @@
2
2
 
3
3
  All notable changes to `@voxevolv/client` are recorded here.
4
4
 
5
+ ## Unreleased
6
+
7
+ ## 0.3.0 - 2026-07-24
8
+
9
+ - Add opt-in SDK-owned recovery with `autoRejoin`, bounded backoff, terminal
10
+ disconnect-reason handling, and the `resuming` connection state.
11
+ - Surface signal-only LiveKit reconnects instead of skipping directly from
12
+ `connected` to readiness restoration.
13
+ - Add `hasConnectedBefore`, `onRecovery()`, `onConnectionQuality()`, and
14
+ `waitForState()`.
15
+ - Make rejoin disconnect based on the underlying LiveKit room state so a
16
+ failed post-reconnect hello cannot leave a connected room in the way.
17
+ - Add configurable lifecycle fetch credentials with a `same-origin` default,
18
+ preserving cookie-authenticated same-origin proxies while omitting cookies
19
+ on direct cross-origin calls.
20
+ - End an in-flight recovery cleanly when the server emits `session.ended`
21
+ instead of leaving the wrapper state at `resuming`.
22
+ - Preserve the outer `rejoin` recovery when late LiveKit reconnect events
23
+ arrive during that attempt, preventing them from moving the wrapper back to
24
+ `reconnecting` and blocking the replacement connection.
25
+ - Preserve the user's microphone mute state across manual and automatic full
26
+ rejoin so recovery never returns with a previously muted microphone enabled.
27
+ - Keep commands pending when the first post-reconnect data publish is rejected,
28
+ allowing the existing retry loop to deliver them once the data channel is
29
+ writable.
30
+
31
+ ## 0.2.0 - 2026-07-20
32
+
33
+ - Add `session.outputStream`: a stable `MediaStream` that always holds the
34
+ agent's current remote audio tracks across track arrival, reconnects, and
35
+ rejoin.
36
+ - `connect()` now also waits for the first remote agent audio track (within
37
+ the same `readyTimeoutMs` budget) before resolving, so media is flowing when
38
+ connect resolves. Pass `waitForRemoteAudio: false` to restore the previous
39
+ signaling-only readiness.
40
+
5
41
  ## 0.1.0 - 2026-07-18
6
42
 
7
43
  - Add application-owned audio-track publication and remote-audio access.
package/README.md CHANGED
@@ -26,7 +26,7 @@ Browsers without a build step can use the versioned bundle after publication:
26
26
  ```html
27
27
  <script type="module">
28
28
  import { RealtimeSession } from
29
- "https://cdn.jsdelivr.net/npm/@voxevolv/client@0.1.0/dist/browser/index.js";
29
+ "https://cdn.jsdelivr.net/npm/@voxevolv/client@0.3.0/dist/browser/index.js";
30
30
  </script>
31
31
  ```
32
32
 
@@ -38,9 +38,10 @@ VoxEvolv session without exposing an organization API key:
38
38
  ```ts
39
39
  const session = await RealtimeSession.create({
40
40
  endpoint: "/api/voice-session",
41
- // Recommended: expose the scoped lifecycle routes through your backend.
42
- // An allowlisted absolute VoxEvolv API URL is also supported.
43
- apiBase: "/api/voxevolv/v1",
41
+ // Use the hosted API directly when its lifecycle CORS policy is public.
42
+ // A same-origin lifecycle proxy remains supported.
43
+ apiBase: "https://YOUR_VOXEVOLV_HOST/v1",
44
+ autoRejoin: true,
44
45
  tools: {
45
46
  present_attachment: (arguments_) => presentAttachment(arguments_),
46
47
  },
@@ -60,7 +61,8 @@ play remote audio:
60
61
 
61
62
  ```ts
62
63
  const session = new RealtimeSession(credentials, {
63
- connect: { apiBase: "/api/voxevolv/v1" },
64
+ connect: { apiBase: "https://YOUR_VOXEVOLV_HOST/v1" },
65
+ autoRejoin: true,
64
66
  });
65
67
  await session.connect({ microphone: true });
66
68
  ```
@@ -100,11 +102,59 @@ a native `MediaStreamTrack` and single-track `MediaStream` for recording,
100
102
  metering, or another application-owned audio graph. Both listener registration
101
103
  methods return an unsubscribe function.
102
104
 
103
- ## Rejoin and end
105
+ ## Agent audio readiness
104
106
 
105
- `rejoin()` can be called from a connected or disconnected state. It obtains a
106
- fresh room token, disconnects an existing room connection when necessary, and
107
- reconnects with the original microphone or application-owned track choice.
107
+ By default `connect()` resolves only after the agent reported readiness *and*
108
+ the first remote agent audio track arrived, both within the same
109
+ `readyTimeoutMs` budget (15 s by default). Agent media is therefore already
110
+ flowing when `connect()` resolves, so recording or metering set up right after
111
+ `connect()` does not race track arrival.
112
+
113
+ `session.outputStream` is a stable `MediaStream` available from session
114
+ creation. The stream object never changes; remote agent audio tracks are added
115
+ when they arrive and removed when they end, including across `rejoin()` and
116
+ reconnects. Note that Web Audio's `createMediaStreamSource()` requires the
117
+ stream to already contain an audio track, so audio-graph consumers should
118
+ still attach inside `onRemoteAudioTrack`.
119
+
120
+ Applications that intentionally run without agent audio can opt out:
121
+
122
+ ```ts
123
+ await session.connect({ waitForRemoteAudio: false });
124
+ ```
125
+
126
+ ## Recovery, rejoin, and connection quality
127
+
128
+ Set `autoRejoin: true` to let the SDK own recovery after LiveKit exhausts its
129
+ transport-level reconnect. Automatic recovery runs only after the session has
130
+ connected successfully, never after an explicit `disconnect()`, `end()`, or
131
+ terminal LiveKit removal. It waits for browser connectivity, obtains a fresh
132
+ room token, and retries with bounded backoff.
133
+
134
+ ```ts
135
+ session.onStateChange((state) => {
136
+ // reconnecting: LiveKit is restoring transport
137
+ // resuming: VoxEvolv is restoring readiness with a fresh connection
138
+ renderConnectionState(state);
139
+ });
140
+
141
+ session.onRecovery(({ status, strategy, attempt, error }) => {
142
+ recordRecovery({ status, strategy, attempt, error });
143
+ });
144
+
145
+ session.onConnectionQuality((quality) => {
146
+ renderCallQuality(quality);
147
+ });
148
+ ```
149
+
150
+ `session.hasConnectedBefore` distinguishes recovery from initial setup.
151
+ `waitForState(states, timeoutMs, { signal })` is available for advanced flows
152
+ that need to await a bounded set of lifecycle states.
153
+
154
+ Manual `rejoin()` remains available. It obtains a fresh room token, disconnects
155
+ any underlying room connection, and reconnects with the original microphone or
156
+ application-owned track choice. A managed microphone that the user muted with
157
+ `setMicrophoneEnabled(false)` remains muted after rejoin.
108
158
 
109
159
  ```ts
110
160
  await session.rejoin();
@@ -113,8 +163,8 @@ await session.end();
113
163
 
114
164
  `RealtimeSession.create()` requires `apiBase` because rejoin, durable replay,
115
165
  and scoped ending happen after the application-owned creation request. Set it
116
- to either an explicit absolute VoxEvolv `/v1` base whose deployment allowlists
117
- the application origin, or a same-origin proxy base that forwards only:
166
+ to either an explicit absolute VoxEvolv `/v1` base (browser lifecycle access is
167
+ enabled by default), or a same-origin proxy base that forwards only:
118
168
 
119
169
  - `POST /sessions/{id}/room-tokens`
120
170
  - `GET /sessions/{id}/events`
@@ -123,6 +173,12 @@ the application origin, or a same-origin proxy base that forwards only:
123
173
  The proxy must forward the browser's `Authorization: Bearer vsa_...` header. It
124
174
  must not replace that credential with an organization API key.
125
175
 
176
+ Lifecycle fetches default to `credentials: "same-origin"`. This sends cookies
177
+ to a same-origin proxy but not to an absolute cross-origin VoxEvolv API. Set
178
+ `lifecycleCredentials` only when a custom proxy has a different credential
179
+ policy; cross-origin `include` requires an exact-origin credentialed CORS
180
+ configuration and is incompatible with wildcard CORS.
181
+
126
182
  `end()` uses the browser-safe `vsa_...` credential to end only that session and
127
183
  then leaves the LiveKit room. Pass `endEndpoint` to the constructor or
128
184
  `end({ endpoint })` when application policy requires a backend completion route.