hci-atrium 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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -0
  3. package/dist/atrium.d.ts +522 -0
  4. package/dist/atrium.d.ts.map +1 -0
  5. package/dist/atrium.js +806 -0
  6. package/dist/atrium.js.map +1 -0
  7. package/dist/auth.d.ts +85 -0
  8. package/dist/auth.d.ts.map +1 -0
  9. package/dist/auth.js +369 -0
  10. package/dist/auth.js.map +1 -0
  11. package/dist/by.d.ts +84 -0
  12. package/dist/by.d.ts.map +1 -0
  13. package/dist/by.js +87 -0
  14. package/dist/by.js.map +1 -0
  15. package/dist/decider.d.ts +40 -0
  16. package/dist/decider.d.ts.map +1 -0
  17. package/dist/decider.js +76 -0
  18. package/dist/decider.js.map +1 -0
  19. package/dist/discovery.d.ts +15 -0
  20. package/dist/discovery.d.ts.map +1 -0
  21. package/dist/discovery.js +38 -0
  22. package/dist/discovery.js.map +1 -0
  23. package/dist/env.d.ts +11 -0
  24. package/dist/env.d.ts.map +1 -0
  25. package/dist/env.js +28 -0
  26. package/dist/env.js.map +1 -0
  27. package/dist/errors.d.ts +67 -0
  28. package/dist/errors.d.ts.map +1 -0
  29. package/dist/errors.js +86 -0
  30. package/dist/errors.js.map +1 -0
  31. package/dist/files.d.ts +7 -0
  32. package/dist/files.d.ts.map +1 -0
  33. package/dist/files.js +2 -0
  34. package/dist/files.js.map +1 -0
  35. package/dist/http.d.ts +11 -0
  36. package/dist/http.d.ts.map +1 -0
  37. package/dist/http.js +21 -0
  38. package/dist/http.js.map +1 -0
  39. package/dist/index.d.ts +17 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +14 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/models.d.ts +456 -0
  44. package/dist/models.d.ts.map +1 -0
  45. package/dist/models.js +487 -0
  46. package/dist/models.js.map +1 -0
  47. package/dist/pkce.d.ts +16 -0
  48. package/dist/pkce.d.ts.map +1 -0
  49. package/dist/pkce.js +40 -0
  50. package/dist/pkce.js.map +1 -0
  51. package/dist/react/index.d.ts +37 -0
  52. package/dist/react/index.d.ts.map +1 -0
  53. package/dist/react/index.js +89 -0
  54. package/dist/react/index.js.map +1 -0
  55. package/dist/rooms/armed-set.d.ts +33 -0
  56. package/dist/rooms/armed-set.d.ts.map +1 -0
  57. package/dist/rooms/armed-set.js +65 -0
  58. package/dist/rooms/armed-set.js.map +1 -0
  59. package/dist/rooms/brokers.d.ts +62 -0
  60. package/dist/rooms/brokers.d.ts.map +1 -0
  61. package/dist/rooms/brokers.js +109 -0
  62. package/dist/rooms/brokers.js.map +1 -0
  63. package/dist/rooms/codec.d.ts +100 -0
  64. package/dist/rooms/codec.d.ts.map +1 -0
  65. package/dist/rooms/codec.js +101 -0
  66. package/dist/rooms/codec.js.map +1 -0
  67. package/dist/rooms/index.d.ts +40 -0
  68. package/dist/rooms/index.d.ts.map +1 -0
  69. package/dist/rooms/index.js +45 -0
  70. package/dist/rooms/index.js.map +1 -0
  71. package/dist/rooms/offer-capture.d.ts +96 -0
  72. package/dist/rooms/offer-capture.d.ts.map +1 -0
  73. package/dist/rooms/offer-capture.js +338 -0
  74. package/dist/rooms/offer-capture.js.map +1 -0
  75. package/dist/rooms/offer-transcription.d.ts +63 -0
  76. package/dist/rooms/offer-transcription.d.ts.map +1 -0
  77. package/dist/rooms/offer-transcription.js +231 -0
  78. package/dist/rooms/offer-transcription.js.map +1 -0
  79. package/dist/rooms/participant.d.ts +35 -0
  80. package/dist/rooms/participant.d.ts.map +1 -0
  81. package/dist/rooms/participant.js +53 -0
  82. package/dist/rooms/participant.js.map +1 -0
  83. package/dist/rooms/recorder.d.ts +74 -0
  84. package/dist/rooms/recorder.d.ts.map +1 -0
  85. package/dist/rooms/recorder.js +157 -0
  86. package/dist/rooms/recorder.js.map +1 -0
  87. package/dist/rooms/room.d.ts +542 -0
  88. package/dist/rooms/room.d.ts.map +1 -0
  89. package/dist/rooms/room.js +1357 -0
  90. package/dist/rooms/room.js.map +1 -0
  91. package/dist/rooms/snippet.d.ts +48 -0
  92. package/dist/rooms/snippet.d.ts.map +1 -0
  93. package/dist/rooms/snippet.js +70 -0
  94. package/dist/rooms/snippet.js.map +1 -0
  95. package/dist/rooms/sse.d.ts +102 -0
  96. package/dist/rooms/sse.d.ts.map +1 -0
  97. package/dist/rooms/sse.js +347 -0
  98. package/dist/rooms/sse.js.map +1 -0
  99. package/dist/rooms/standing-source.d.ts +190 -0
  100. package/dist/rooms/standing-source.d.ts.map +1 -0
  101. package/dist/rooms/standing-source.js +431 -0
  102. package/dist/rooms/standing-source.js.map +1 -0
  103. package/dist/rooms/transcriber.d.ts +81 -0
  104. package/dist/rooms/transcriber.d.ts.map +1 -0
  105. package/dist/rooms/transcriber.js +111 -0
  106. package/dist/rooms/transcriber.js.map +1 -0
  107. package/dist/rooms/transport-shared.d.ts +28 -0
  108. package/dist/rooms/transport-shared.d.ts.map +1 -0
  109. package/dist/rooms/transport-shared.js +42 -0
  110. package/dist/rooms/transport-shared.js.map +1 -0
  111. package/dist/rooms/transport.d.ts +161 -0
  112. package/dist/rooms/transport.d.ts.map +1 -0
  113. package/dist/rooms/transport.js +258 -0
  114. package/dist/rooms/transport.js.map +1 -0
  115. package/dist/shaping/assets.d.ts +42 -0
  116. package/dist/shaping/assets.d.ts.map +1 -0
  117. package/dist/shaping/assets.js +77 -0
  118. package/dist/shaping/assets.js.map +1 -0
  119. package/dist/shaping/chat.d.ts +39 -0
  120. package/dist/shaping/chat.d.ts.map +1 -0
  121. package/dist/shaping/chat.js +62 -0
  122. package/dist/shaping/chat.js.map +1 -0
  123. package/dist/shaping/index.d.ts +14 -0
  124. package/dist/shaping/index.d.ts.map +1 -0
  125. package/dist/shaping/index.js +13 -0
  126. package/dist/shaping/index.js.map +1 -0
  127. package/dist/shaping/library.d.ts +84 -0
  128. package/dist/shaping/library.d.ts.map +1 -0
  129. package/dist/shaping/library.js +288 -0
  130. package/dist/shaping/library.js.map +1 -0
  131. package/dist/shaping/request.d.ts +47 -0
  132. package/dist/shaping/request.d.ts.map +1 -0
  133. package/dist/shaping/request.js +25 -0
  134. package/dist/shaping/request.js.map +1 -0
  135. package/dist/shaping/rooms.d.ts +128 -0
  136. package/dist/shaping/rooms.d.ts.map +1 -0
  137. package/dist/shaping/rooms.js +330 -0
  138. package/dist/shaping/rooms.js.map +1 -0
  139. package/dist/shaping/sources.d.ts +29 -0
  140. package/dist/shaping/sources.d.ts.map +1 -0
  141. package/dist/shaping/sources.js +51 -0
  142. package/dist/shaping/sources.js.map +1 -0
  143. package/dist/shaping/structured.d.ts +47 -0
  144. package/dist/shaping/structured.d.ts.map +1 -0
  145. package/dist/shaping/structured.js +115 -0
  146. package/dist/shaping/structured.js.map +1 -0
  147. package/dist/storage.d.ts +36 -0
  148. package/dist/storage.d.ts.map +1 -0
  149. package/dist/storage.js +86 -0
  150. package/dist/storage.js.map +1 -0
  151. package/dist/transcribe-stream.d.ts +81 -0
  152. package/dist/transcribe-stream.d.ts.map +1 -0
  153. package/dist/transcribe-stream.js +253 -0
  154. package/dist/transcribe-stream.js.map +1 -0
  155. package/dist/transcribe.d.ts +57 -0
  156. package/dist/transcribe.d.ts.map +1 -0
  157. package/dist/transcribe.js +267 -0
  158. package/dist/transcribe.js.map +1 -0
  159. package/dist/types.d.ts +20 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +3 -0
  162. package/dist/types.js.map +1 -0
  163. package/package.json +56 -0
@@ -0,0 +1,347 @@
1
+ /**
2
+ * The room's **SSE-receive + POST-send** transport — the fallback the {@link ./room.Room} uses when
3
+ * the WebSocket ({@link ./transport.RoomSocket}) can't come up (a reverse proxy that strips WS
4
+ * upgrades, like the production HULK edge, looks exactly like a WS that never reaches ``ready``).
5
+ *
6
+ * This is the port of the Python SDK's SSE dispatcher (``aio.py``'s ``_RoomDispatcher`` +
7
+ * ``rooms.py``'s ``_events`` / ``_stream_params``): receive live signals over
8
+ * ``GET /v1/rooms/{id}/events`` (SSE), send over ``POST /v1/rooms/{id}/signal``. Both directions
9
+ * authorize with the **connect code** — the SSE read passes ``?code=``, the signal POST passes it in
10
+ * the ``X-Session-Code`` header — so it works for a host (its own room's code) and a loginless
11
+ * participant alike, and needs no bearer/streaming-auth plumbing (mirror of the WS route's code-only
12
+ * auth). Native ``EventSource`` can't set headers or read a POST body, so this uses streaming
13
+ * ``fetch`` (``res.body`` reader), which handles code-auth uniformly in browser and Node.
14
+ *
15
+ * Limits vs. WS (documented, same as Python): **signals only** — a room's ephemeral *binary* audio
16
+ * stream rides the WS exclusively, so {@link sendBinary} is a no-op and audio consumers
17
+ * (``audioSignals`` / ``audioClips``) stay WS-only. Rooms have **no replay** (the events stream
18
+ * carries no ``id:`` cursor), so a dropped stream reconnects with backoff and misses the gap — there
19
+ * is nothing to resume with ``Last-Event-ID`` (that cursor is a session-stream feature, not a room's).
20
+ * A ``room.code_rotated`` signal (or the terminal 403/404) ends the stream for good.
21
+ */
22
+ import { httpFetch } from "../http.js";
23
+ import { buildRoomSignal } from "../shaping/rooms.js";
24
+ import { backoffDelay, CONNECT_TIMEOUT_MS, ReadyWaiters } from "./transport-shared.js";
25
+ const ROOM_CODE_ROTATED = "room.code_rotated";
26
+ function eventsUrl(o) {
27
+ const base = o.baseUrl.replace(/\/+$/, "");
28
+ const params = new URLSearchParams({ code: o.code });
29
+ if (o.observe) {
30
+ // An observer taps the feed silently — no presence identity/announce, just the observe flag.
31
+ params.set("observe", "1");
32
+ }
33
+ else {
34
+ if (o.identity)
35
+ params.set("identity", o.identity);
36
+ if (o.announce)
37
+ params.set("announce", JSON.stringify(o.announce));
38
+ }
39
+ return `${base}/v1/rooms/${o.roomId}/events?${params.toString()}`;
40
+ }
41
+ function mapRosterEntry(raw) {
42
+ return {
43
+ connectionId: raw.connection_id ?? "",
44
+ identity: raw.identity,
45
+ announce: raw.announce,
46
+ connectedAt: raw.connected_at,
47
+ };
48
+ }
49
+ /**
50
+ * Parse a byte stream of Server-Sent Events into ``{event, data}`` frames (one per blank-line
51
+ * boundary) — the async-generator mirror of Python's ``_aparse_sse``. Comment lines (``:`` — the
52
+ * keepalives) are skipped; multiple ``data:`` lines join with newlines; ``id:`` is ignored (a room
53
+ * stream has no replay cursor).
54
+ */
55
+ export async function* sseFrames(reader) {
56
+ const decoder = new TextDecoder();
57
+ let buffer = "";
58
+ let event = "message";
59
+ let data = [];
60
+ while (true) {
61
+ const { value, done } = await reader.read();
62
+ if (done)
63
+ break;
64
+ buffer += decoder.decode(value, { stream: true });
65
+ // Scan line-by-line with a moving cursor, slicing only each line out (not the whole tail per
66
+ // line) — the old ``buffer = buffer.slice(nl + 1)`` re-copied the remaining buffer on every line,
67
+ // going quadratic on a burst. The consumed prefix is dropped once, after the chunk is scanned.
68
+ let start = 0;
69
+ let nl = buffer.indexOf("\n", start);
70
+ while (nl >= 0) {
71
+ let end = nl;
72
+ if (end > start && buffer.charCodeAt(end - 1) === 13)
73
+ end -= 1; // strip a trailing \r
74
+ const line = buffer.slice(start, end);
75
+ if (line === "") {
76
+ if (data.length > 0)
77
+ yield { event, data: data.join("\n") };
78
+ event = "message";
79
+ data = [];
80
+ }
81
+ else if (line.startsWith(":")) {
82
+ // keepalive / comment — ignore
83
+ }
84
+ else if (line.startsWith("event:")) {
85
+ event = line.slice("event:".length).trim();
86
+ }
87
+ else if (line.startsWith("data:")) {
88
+ data.push(line.slice("data:".length).replace(/^ /, ""));
89
+ }
90
+ // `id:` deliberately ignored — rooms have no replay.
91
+ start = nl + 1;
92
+ nl = buffer.indexOf("\n", start);
93
+ }
94
+ if (start > 0)
95
+ buffer = buffer.slice(start);
96
+ }
97
+ }
98
+ export class RoomEventStream {
99
+ opts;
100
+ connId = null;
101
+ roster = [];
102
+ closed = false;
103
+ attempt = 0;
104
+ everReady = false;
105
+ controller = null;
106
+ retryTimer = null;
107
+ // True while runLoop is alive — connect() restarts a *dead* loop instead of adding a waiter that
108
+ // would never resolve (the double-open guard ported from the WS transport). A live loop just gets
109
+ // the new waiter.
110
+ looping = false;
111
+ readyWaiters = new ReadyWaiters();
112
+ fetchImpl;
113
+ constructor(opts) {
114
+ this.opts = opts;
115
+ this.fetchImpl = opts.fetchImpl ?? httpFetch;
116
+ }
117
+ connectionId() {
118
+ return this.connId;
119
+ }
120
+ participants() {
121
+ return [...this.roster];
122
+ }
123
+ connect() {
124
+ if (this.everReady)
125
+ return Promise.resolve();
126
+ // A closed stream never reopens — reject at once (the connect-after-close race, mirror of
127
+ // RoomSocket.connect) rather than start a loop that a set ``closed`` flag would abandon.
128
+ if (this.closed)
129
+ return Promise.reject(new Error("room closed"));
130
+ const promise = new Promise((resolve, reject) => {
131
+ this.readyWaiters.add(resolve, reject);
132
+ });
133
+ if (!this.looping) {
134
+ void this.runLoop();
135
+ const timer = setTimeout(() => {
136
+ this.readyWaiters.rejectAll(new Error(`room stream not ready within ${CONNECT_TIMEOUT_MS / 1000}s`));
137
+ }, CONNECT_TIMEOUT_MS);
138
+ void promise.finally(() => clearTimeout(timer)).catch(() => { });
139
+ }
140
+ return promise;
141
+ }
142
+ /** Send a text signal over ``POST /v1/rooms/{id}/signal`` — fire-and-forget (mirror of the WS
143
+ * ``sendSignal``: a failure is swallowed, like a WS send dropped while momentarily down). */
144
+ sendSignal(sig) {
145
+ const { json } = buildRoomSignal(this.opts.roomId, {
146
+ type: sig.type,
147
+ payload: sig.payload,
148
+ to: sig.to,
149
+ includeSelf: sig.includeSelf,
150
+ source: sig.source,
151
+ ackId: sig.ackId,
152
+ replyTo: sig.replyTo,
153
+ connectionId: this.connId,
154
+ });
155
+ const base = this.opts.baseUrl.replace(/\/+$/, "");
156
+ void this.fetchImpl(`${base}/v1/rooms/${this.opts.roomId}/signal`, {
157
+ method: "POST",
158
+ headers: { "Content-Type": "application/json", "X-Session-Code": this.opts.code },
159
+ body: JSON.stringify(json),
160
+ }).catch(() => { });
161
+ }
162
+ /** SSE carries no binary — audio consumers stay WS-only. A no-op, so a Room in SSE fallback never
163
+ * throws on the (unused) binary path. */
164
+ sendBinary(_data) { }
165
+ close() {
166
+ this.closed = true;
167
+ if (this.retryTimer)
168
+ clearTimeout(this.retryTimer);
169
+ this.retryTimer = null;
170
+ this.controller?.abort();
171
+ this.controller = null;
172
+ this.readyWaiters.rejectAll(new Error("room closed"));
173
+ }
174
+ async runLoop() {
175
+ this.looping = true;
176
+ try {
177
+ await this.loop();
178
+ }
179
+ finally {
180
+ this.looping = false;
181
+ }
182
+ }
183
+ async loop() {
184
+ while (!this.closed) {
185
+ const controller = new AbortController();
186
+ this.controller = controller;
187
+ let rotationSeen = false;
188
+ try {
189
+ const res = await this.fetchImpl(eventsUrl(this.opts), {
190
+ method: "GET",
191
+ headers: { Accept: "text/event-stream" },
192
+ signal: controller.signal,
193
+ });
194
+ if (!res.ok) {
195
+ if (this.handleHttpError(res.status))
196
+ return; // terminal (403/404) — stop
197
+ // else fall through to backoff (429 / 5xx / transient)
198
+ }
199
+ else if (res.body) {
200
+ const reader = res.body.getReader();
201
+ for await (const frame of sseFrames(reader)) {
202
+ if (this.closed)
203
+ return;
204
+ if (frame.event === "ready") {
205
+ this.onReadyFrame(frame.data);
206
+ }
207
+ else if (frame.event === "signal") {
208
+ // Await the dispatch inline — a promise-returning onSignal (the recorder's inline
209
+ // session-event write) throttles the reader here, so recorded events can't lag
210
+ // unboundedly. A rejection falls through to the catch below (backoff + reconnect).
211
+ rotationSeen = (await this.onSignalFrame(frame.data)) || rotationSeen;
212
+ }
213
+ }
214
+ // The stream ended. A code rotation is the one clean terminal end (the server broadcasts
215
+ // ``room.code_rotated`` then closes the stream — there is no SSE close code, so the signal
216
+ // is the in-band 4410 equivalent). Otherwise the stream just dropped: reconnect (no replay).
217
+ if (rotationSeen) {
218
+ this.opts.onEnd?.("code-rotated");
219
+ return;
220
+ }
221
+ }
222
+ }
223
+ catch (err) {
224
+ if (this.closed || err?.name === "AbortError")
225
+ return;
226
+ // network/transient error — fall through to backoff
227
+ }
228
+ this.everReady = false;
229
+ if (this.opts.reconnect === false) {
230
+ this.readyWaiters.rejectAll(new Error("room stream closed before ready"));
231
+ return;
232
+ }
233
+ await this.backoff();
234
+ }
235
+ }
236
+ // Map an HTTP error to a terminal reason (mirror of the WS 4404/4403 close codes + Python's blanket
237
+ // rule: any status < 500 except 429 is terminal — the server refused us and no retry will heal it).
238
+ // Returns true if terminal (stop the loop); 429 (the code-throttle window) and 5xx are transient.
239
+ handleHttpError(status) {
240
+ if (status >= 500 || status === 429)
241
+ return false; // transient — backoff + retry
242
+ // A gone room reads as room-gone; every other refusal (401/403/400/410/…) as a rejected code.
243
+ this.terminate(status === 404 ? "room-gone" : "bad-code");
244
+ return true;
245
+ }
246
+ terminate(reason) {
247
+ if (!this.everReady)
248
+ this.readyWaiters.rejectAll(new Error(`room connection ended: ${reason}`));
249
+ this.opts.onEnd?.(reason);
250
+ }
251
+ onReadyFrame(data) {
252
+ let msg;
253
+ try {
254
+ msg = JSON.parse(data);
255
+ }
256
+ catch {
257
+ return;
258
+ }
259
+ this.connId = msg.connection_id ?? null;
260
+ this.attempt = 0;
261
+ this.everReady = true;
262
+ this.roster = (msg.participants ?? []).map(mapRosterEntry);
263
+ this.opts.onParticipants?.(this.participants());
264
+ this.readyWaiters.resolveAll();
265
+ if (this.connId)
266
+ this.opts.onReady?.(this.connId);
267
+ }
268
+ // Dispatch one signal frame; returns true if it was the code-rotation advance signal. Awaits
269
+ // onSignal so a consumer's inline write (the recorder) backpressures the read loop.
270
+ async onSignalFrame(data) {
271
+ let sig;
272
+ try {
273
+ sig = JSON.parse(data);
274
+ }
275
+ catch {
276
+ return false;
277
+ }
278
+ this.updateRoster(sig);
279
+ await this.opts.onSignal?.(sig);
280
+ return sig.type === ROOM_CODE_ROTATED;
281
+ }
282
+ updateRoster(sig) {
283
+ const p = sig.payload;
284
+ if (sig.type === "presence.join") {
285
+ if (p?.connection_id && !this.roster.some((x) => x.connectionId === p.connection_id)) {
286
+ this.roster = [...this.roster, mapRosterEntry(p)];
287
+ this.opts.onParticipants?.(this.participants());
288
+ }
289
+ }
290
+ else if (sig.type === "presence.leave") {
291
+ if (p?.connection_id && this.roster.some((x) => x.connectionId === p.connection_id)) {
292
+ this.roster = this.roster.filter((x) => x.connectionId !== p.connection_id);
293
+ this.opts.onParticipants?.(this.participants());
294
+ }
295
+ }
296
+ }
297
+ backoff() {
298
+ const delay = backoffDelay(this.attempt);
299
+ this.attempt += 1;
300
+ return new Promise((resolve) => {
301
+ this.retryTimer = setTimeout(resolve, delay);
302
+ });
303
+ }
304
+ }
305
+ /**
306
+ * Read a room's presence roster off one short **observe** SSE stream and return it parsed — the
307
+ * transport behind ``room.participants()`` / ``room.has()`` (mirror of Python's ``_read_participants``
308
+ * / ``AsyncRoom.participants``). ``observe=1`` taps the feed without minting a presence connection
309
+ * (no phantom join/leave), reads the first ``ready`` frame's roster, then closes. SSE (not WS) because
310
+ * the WS route has no observe mode, and SSE works behind a WS-stripping proxy.
311
+ */
312
+ export async function readObserveRoster(opts) {
313
+ const fetchImpl = opts.fetchImpl ?? httpFetch;
314
+ const base = opts.baseUrl.replace(/\/+$/, "");
315
+ const url = `${base}/v1/rooms/${opts.roomId}/events?${new URLSearchParams({
316
+ code: opts.code,
317
+ observe: "1",
318
+ }).toString()}`;
319
+ const controller = new AbortController();
320
+ const res = await fetchImpl(url, {
321
+ method: "GET",
322
+ headers: { Accept: "text/event-stream" },
323
+ signal: controller.signal,
324
+ });
325
+ if (!res.ok) {
326
+ const detail = await res.text().catch(() => "");
327
+ controller.abort();
328
+ throw new Error(`room roster read failed (${res.status})${detail ? `: ${detail}` : ""}`);
329
+ }
330
+ if (!res.body) {
331
+ return [];
332
+ }
333
+ const reader = res.body.getReader();
334
+ try {
335
+ for await (const frame of sseFrames(reader)) {
336
+ if (frame.event === "ready") {
337
+ const msg = JSON.parse(frame.data);
338
+ return msg.participants ?? [];
339
+ }
340
+ }
341
+ return [];
342
+ }
343
+ finally {
344
+ controller.abort();
345
+ }
346
+ }
347
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/rooms/sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * The shared harness for the two peer-toggleable standing offers (``offerTranscription`` /
3
+ * ``offerAudioCapture``) — the TypeScript port of Python's ``_StandingSource`` (aio.py). Everything
4
+ * the multi-mic scoping needs that isn't specific to *what* a source's frames do (transcribe vs
5
+ * record):
6
+ *
7
+ * * the {@link ArmedSet} and the ``maxSources`` cap admission ({@link StandingSource.tryArm}) plus
8
+ * warn-once cap logging;
9
+ * * the ``active`` roster + {@link StandingSource.status}, built on the **armed set** (not on audio
10
+ * flow — a source appears the moment it is armed; an all-arm enumerates every currently-connected
11
+ * ``capture-source`` from the presence roster, kept current on join/leave);
12
+ * * broadcast dedup + fire-and-forget spawn, over the REST ``/signal`` POST (the WS inbound path
13
+ * forces ``ephemeral: false``, so an ephemeral ``*.available`` broadcast must ride REST);
14
+ * * the departed-source grace bookkeeping and the **single** periodic sweeper (one timer — not a
15
+ * timer per departure) that finalizes/expires grace;
16
+ * * arm **migration** on a same-name reconnect so a per-source-armed device that drops and returns
17
+ * within grace stays admitted;
18
+ * * the generic scoped ``start`` / ``stopRequest`` shells, dispatching to per-offer hooks.
19
+ *
20
+ * Subclasses provide ``signal`` / ``logName`` / ``identityPrefix`` and override the hooks:
21
+ * {@link StandingSource.run}, {@link StandingSource.stop}, {@link StandingSource.stopSource},
22
+ * {@link StandingSource.beforeArm}, {@link StandingSource.onEngage}, {@link StandingSource.activeExtra},
23
+ * {@link StandingSource.onPresenceSource}, {@link StandingSource.onGraceExpired}.
24
+ */
25
+ import { ArmedSet } from "./armed-set.js";
26
+ import { RoomSocket, type WebSocketCtor } from "./transport.js";
27
+ /** Max clips buffered per source before an offered transcription's demux drops the *oldest* (live
28
+ * captions favour recency; a stalled engine must not grow memory without bound). */
29
+ export declare const OFFER_CLIP_QUEUE_MAX = 8;
30
+ /** Safety bound on the pre-demux frame queue — only BINARY frames are dropped (oldest-first) past
31
+ * this; control/presence/end frames are never dropped (they carry roster + teardown state). Generous
32
+ * because the demux normally drains it at once; it exists to cap a pathological producer flood. */
33
+ export declare const OFFER_EVENT_QUEUE_MAX = 256;
34
+ /** Consecutive failed recording-creates for one capture source before it is dropped. */
35
+ export declare const CAPTURE_CREATE_MAX_FAILURES = 3;
36
+ /** Default cap on concurrently-active sources per offer (multi-mic safety). */
37
+ export declare const OFFER_MAX_SOURCES = 8;
38
+ /** Grace window (seconds) an offered-capture recording stays open after its source departs, so a
39
+ * same-name reconnect within it resumes the very same file. Elapsed with no return → it finalizes. */
40
+ export declare const SOURCE_GRACE_SECONDS = 120;
41
+ /** How often the single grace sweeper wakes to scan departure timestamps (coarse — grace is minutes). */
42
+ export declare const GRACE_SWEEP_SECONDS = 5;
43
+ /** One entry of a standing offer's ``active`` roster: an armed source, human-labelled if known. */
44
+ export interface ActiveSource {
45
+ source: string | null;
46
+ name: string | null;
47
+ }
48
+ /** What every standing offer is wired with (filled by {@link ./room.Room}). */
49
+ export interface OfferDeps {
50
+ roomId: string;
51
+ /** Read the room's current connect code (it can rotate) — the snippet socket's ``?code=`` auth. */
52
+ getCode(): string;
53
+ baseUrl: string;
54
+ reconnect?: boolean;
55
+ WebSocketCtor?: WebSocketCtor;
56
+ /** Publish a room signal over the REST ``/signal`` POST — preserves ``ephemeral`` (unlike the WS
57
+ * inbound path, which forces ``ephemeral: false``). Used for ``*.available`` broadcasts and the
58
+ * per-source ``transcript.*`` publishes. */
59
+ publishSignal(type: string, payload: Record<string, unknown>, opts: {
60
+ source?: string | null;
61
+ ephemeral?: boolean;
62
+ }): Promise<void>;
63
+ /** Refuse fast (throw {@link ../errors.AtriumError}) if the room handle latched onto the SSE
64
+ * transport — binary audio is WS-only, so the offer must not open a doomed snippet socket that
65
+ * spins a WS reconnect forever. Consulted at engage time (before the frame loop launches). */
66
+ requireWsAudio?(): void;
67
+ }
68
+ /** A minimal async mutex — serializes state transitions (start / stop / grace-finalize / disengage),
69
+ * the port of the offers' ``asyncio.Lock``. */
70
+ export declare class Mutex {
71
+ private tail;
72
+ run<T>(fn: () => Promise<T>): Promise<T>;
73
+ }
74
+ export declare abstract class StandingSource {
75
+ protected readonly signal: string;
76
+ protected readonly logName: string;
77
+ protected readonly identityPrefix: string;
78
+ protected readonly deps: OfferDeps;
79
+ protected readonly maxSources: number;
80
+ protected readonly armed: ArmedSet;
81
+ protected readonly lock: Mutex;
82
+ /** Grace window (seconds) — a per-instance override of {@link SOURCE_GRACE_SECONDS} (tests set 0). */
83
+ graceSeconds: number;
84
+ /** Sweeper interval (seconds) — overridable for tests. */
85
+ sweepSeconds: number;
86
+ protected ws: RoomSocket | null;
87
+ protected runPromise: Promise<void> | null;
88
+ protected settled: boolean;
89
+ protected err: Error | null;
90
+ /** Set when the offer wound down because the room rotated its connect code (a controlled end, not
91
+ * an error — {@link error} stays ``null``). */
92
+ stoppedReason: string | null;
93
+ /** True once the frame stream ended via a ``room.code_rotated`` advance-signal / close. */
94
+ protected codeRotated: boolean;
95
+ /** Connection ids refused admission by the source cap — warned once each. */
96
+ protected readonly cappedWarned: Set<string | null>;
97
+ /** Background broadcast promises spun off the (sync) presence hook — settled at teardown. */
98
+ protected readonly bg: Promise<void>[];
99
+ /** The last ``(available, active)`` broadcast — dedupes the ``*.available`` signal. */
100
+ private lastBroadcast;
101
+ /** connection id → last-known announced name, kept across a leave for the grace window. */
102
+ protected readonly sourceNames: Map<string, string | null>;
103
+ /** departed connection id → leave time (ms) — the grace window a same-name return resumes within. */
104
+ protected readonly departed: Map<string, number>;
105
+ /** The offer's OWN point-in-time roster (name + roles), seeded from the ready snapshot and folded
106
+ * in loop order by {@link onPresence} — the port of ``RoomWebSocket``'s own ``_names`` / ``_roles``.
107
+ * Read (not the transport's live roster) so a burst of presence + binary resolves each frame's
108
+ * source against the roster *as it was when that frame was processed*. */
109
+ private readonly roster;
110
+ private rosterSeeded;
111
+ private eventQueue;
112
+ private binaryQueued;
113
+ private eventWake;
114
+ private sweepTimer;
115
+ constructor(deps: OfferDeps, maxSources?: number);
116
+ /** True while the offer is engaged (the snippet subscription loop runs). */
117
+ get alive(): boolean;
118
+ /** The error that ended the offer for good (``null`` while armed or after ``stop()``). */
119
+ get error(): Error | null;
120
+ /** Availability as it rides ``<service>.status`` / ``<service>.available``. The default
121
+ * (transcription) is available unless the loop died on a terminal error; capture overrides to also
122
+ * require an active recorder. */
123
+ available(): boolean;
124
+ protected isDeparted(cid: string): boolean;
125
+ protected nameFor(cid: string): string | null;
126
+ protected connectionIdsWithRole(role: string): string[];
127
+ private armedActive;
128
+ /** Per-offer additions to the armed roster (the honesty entry for a v1 id-less source). */
129
+ protected activeExtra(): ActiveSource[];
130
+ protected active(): ActiveSource[];
131
+ /** The ``<service>.status`` reply payload (sans the outer ``ok``). */
132
+ status(): {
133
+ available: boolean;
134
+ active: ActiveSource[];
135
+ };
136
+ protected broadcast(): Promise<void>;
137
+ protected clearLastBroadcast(): void;
138
+ protected spawnBroadcast(): void;
139
+ protected tryArm(source: string | null, armAll: boolean): void;
140
+ protected warnCapped(cid: string | null): void;
141
+ /** Open the snippet-subscription WebSocket, seed the departed-name roster, and launch the single
142
+ * grace sweeper. Each ``run`` calls this at its top. */
143
+ protected openWs(): Promise<RoomSocket>;
144
+ private seedRoster;
145
+ private foldPresence;
146
+ private pushEvent;
147
+ /** Yield the snippet-consumer socket's binary frames while folding ``presence.join`` /
148
+ * ``presence.leave`` into the live roster + arm migration (the port of Python's
149
+ * ``RoomWebSocket.frames(on_presence=...)``). Ends when the socket ends. */
150
+ protected frames(): AsyncGenerator<ArrayBuffer>;
151
+ protected startSweeper(): void;
152
+ protected stopSweeper(): void;
153
+ /** One grace pass: finalize/expire each source whose grace window elapsed with no return. Public
154
+ * so a test can drive a pass directly (mirror of Python's ``_sweep_once``). */
155
+ sweepOnce(): Promise<void>;
156
+ /** Per-offer grace-expiry action (capture finalizes the departed recording; default: none). */
157
+ protected onGraceExpired(_cid: string): Promise<void>;
158
+ protected onPresence(event: "join" | "leave", cid: string, announce?: Record<string, unknown>): void;
159
+ private migrateArmOnRejoin;
160
+ /** Per-offer presence bookkeeping (transcription reaps the source's engine on leave; capture
161
+ * leans on the shared grace machinery, so it's a no-op). Default: none. */
162
+ protected onPresenceSource(_event: "join" | "leave", _cid: string): void;
163
+ /** Arm a source (idempotent) and launch the frame loop on the first arm. Scoped to ``source``
164
+ * unless ``all`` (or an unscoped ``source=null`` — the v1 rule). Refuses a new per-source arm past
165
+ * the cap; a per-offer {@link beforeArm} may refuse for another reason (capture: no recorder).
166
+ * Broadcasts the armed-set change immediately, so a device sees itself active before a frame. */
167
+ start({ source, all, }?: {
168
+ source?: string | null;
169
+ all?: boolean;
170
+ }): Promise<void>;
171
+ /** Per-offer pre-arm check, returning a context passed to {@link onEngage} on first launch. */
172
+ protected beforeArm(_armAll: boolean): Promise<unknown>;
173
+ /** Per-offer first-launch setup under the lock (capture binds the recorder; else none). */
174
+ protected onEngage(_ctx: unknown): void;
175
+ /** The wire ``<service>.stop``. ``all`` (or an unscoped call) is the full teardown; otherwise
176
+ * disarm ``source`` alone, leaving the rest. */
177
+ stopRequest({ source, all, }?: {
178
+ source?: string | null;
179
+ all?: boolean;
180
+ }): Promise<void>;
181
+ /** Per-offer single-source stop — provided by the subclass. */
182
+ protected abstract stopSource(source: string): Promise<void>;
183
+ /** Per-offer full teardown — provided by the subclass. */
184
+ abstract stop(): Promise<void>;
185
+ /** Per-offer frame loop — provided by the subclass. */
186
+ protected abstract run(): Promise<void>;
187
+ [Symbol.dispose]: () => void;
188
+ [Symbol.asyncDispose]: () => Promise<void>;
189
+ }
190
+ //# sourceMappingURL=standing-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standing-source.d.ts","sourceRoot":"","sources":["../../src/rooms/standing-source.ts"],"names":[],"mappings":"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"}