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.
- package/LICENSE +21 -0
- package/README.md +182 -0
- package/dist/atrium.d.ts +522 -0
- package/dist/atrium.d.ts.map +1 -0
- package/dist/atrium.js +806 -0
- package/dist/atrium.js.map +1 -0
- package/dist/auth.d.ts +85 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +369 -0
- package/dist/auth.js.map +1 -0
- package/dist/by.d.ts +84 -0
- package/dist/by.d.ts.map +1 -0
- package/dist/by.js +87 -0
- package/dist/by.js.map +1 -0
- package/dist/decider.d.ts +40 -0
- package/dist/decider.d.ts.map +1 -0
- package/dist/decider.js +76 -0
- package/dist/decider.js.map +1 -0
- package/dist/discovery.d.ts +15 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +38 -0
- package/dist/discovery.js.map +1 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +28 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +86 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.d.ts +7 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +2 -0
- package/dist/files.js.map +1 -0
- package/dist/http.d.ts +11 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +21 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +456 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +487 -0
- package/dist/models.js.map +1 -0
- package/dist/pkce.d.ts +16 -0
- package/dist/pkce.d.ts.map +1 -0
- package/dist/pkce.js +40 -0
- package/dist/pkce.js.map +1 -0
- package/dist/react/index.d.ts +37 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +89 -0
- package/dist/react/index.js.map +1 -0
- package/dist/rooms/armed-set.d.ts +33 -0
- package/dist/rooms/armed-set.d.ts.map +1 -0
- package/dist/rooms/armed-set.js +65 -0
- package/dist/rooms/armed-set.js.map +1 -0
- package/dist/rooms/brokers.d.ts +62 -0
- package/dist/rooms/brokers.d.ts.map +1 -0
- package/dist/rooms/brokers.js +109 -0
- package/dist/rooms/brokers.js.map +1 -0
- package/dist/rooms/codec.d.ts +100 -0
- package/dist/rooms/codec.d.ts.map +1 -0
- package/dist/rooms/codec.js +101 -0
- package/dist/rooms/codec.js.map +1 -0
- package/dist/rooms/index.d.ts +40 -0
- package/dist/rooms/index.d.ts.map +1 -0
- package/dist/rooms/index.js +45 -0
- package/dist/rooms/index.js.map +1 -0
- package/dist/rooms/offer-capture.d.ts +96 -0
- package/dist/rooms/offer-capture.d.ts.map +1 -0
- package/dist/rooms/offer-capture.js +338 -0
- package/dist/rooms/offer-capture.js.map +1 -0
- package/dist/rooms/offer-transcription.d.ts +63 -0
- package/dist/rooms/offer-transcription.d.ts.map +1 -0
- package/dist/rooms/offer-transcription.js +231 -0
- package/dist/rooms/offer-transcription.js.map +1 -0
- package/dist/rooms/participant.d.ts +35 -0
- package/dist/rooms/participant.d.ts.map +1 -0
- package/dist/rooms/participant.js +53 -0
- package/dist/rooms/participant.js.map +1 -0
- package/dist/rooms/recorder.d.ts +74 -0
- package/dist/rooms/recorder.d.ts.map +1 -0
- package/dist/rooms/recorder.js +157 -0
- package/dist/rooms/recorder.js.map +1 -0
- package/dist/rooms/room.d.ts +542 -0
- package/dist/rooms/room.d.ts.map +1 -0
- package/dist/rooms/room.js +1357 -0
- package/dist/rooms/room.js.map +1 -0
- package/dist/rooms/snippet.d.ts +48 -0
- package/dist/rooms/snippet.d.ts.map +1 -0
- package/dist/rooms/snippet.js +70 -0
- package/dist/rooms/snippet.js.map +1 -0
- package/dist/rooms/sse.d.ts +102 -0
- package/dist/rooms/sse.d.ts.map +1 -0
- package/dist/rooms/sse.js +347 -0
- package/dist/rooms/sse.js.map +1 -0
- package/dist/rooms/standing-source.d.ts +190 -0
- package/dist/rooms/standing-source.d.ts.map +1 -0
- package/dist/rooms/standing-source.js +431 -0
- package/dist/rooms/standing-source.js.map +1 -0
- package/dist/rooms/transcriber.d.ts +81 -0
- package/dist/rooms/transcriber.d.ts.map +1 -0
- package/dist/rooms/transcriber.js +111 -0
- package/dist/rooms/transcriber.js.map +1 -0
- package/dist/rooms/transport-shared.d.ts +28 -0
- package/dist/rooms/transport-shared.d.ts.map +1 -0
- package/dist/rooms/transport-shared.js +42 -0
- package/dist/rooms/transport-shared.js.map +1 -0
- package/dist/rooms/transport.d.ts +161 -0
- package/dist/rooms/transport.d.ts.map +1 -0
- package/dist/rooms/transport.js +258 -0
- package/dist/rooms/transport.js.map +1 -0
- package/dist/shaping/assets.d.ts +42 -0
- package/dist/shaping/assets.d.ts.map +1 -0
- package/dist/shaping/assets.js +77 -0
- package/dist/shaping/assets.js.map +1 -0
- package/dist/shaping/chat.d.ts +39 -0
- package/dist/shaping/chat.d.ts.map +1 -0
- package/dist/shaping/chat.js +62 -0
- package/dist/shaping/chat.js.map +1 -0
- package/dist/shaping/index.d.ts +14 -0
- package/dist/shaping/index.d.ts.map +1 -0
- package/dist/shaping/index.js +13 -0
- package/dist/shaping/index.js.map +1 -0
- package/dist/shaping/library.d.ts +84 -0
- package/dist/shaping/library.d.ts.map +1 -0
- package/dist/shaping/library.js +288 -0
- package/dist/shaping/library.js.map +1 -0
- package/dist/shaping/request.d.ts +47 -0
- package/dist/shaping/request.d.ts.map +1 -0
- package/dist/shaping/request.js +25 -0
- package/dist/shaping/request.js.map +1 -0
- package/dist/shaping/rooms.d.ts +128 -0
- package/dist/shaping/rooms.d.ts.map +1 -0
- package/dist/shaping/rooms.js +330 -0
- package/dist/shaping/rooms.js.map +1 -0
- package/dist/shaping/sources.d.ts +29 -0
- package/dist/shaping/sources.d.ts.map +1 -0
- package/dist/shaping/sources.js +51 -0
- package/dist/shaping/sources.js.map +1 -0
- package/dist/shaping/structured.d.ts +47 -0
- package/dist/shaping/structured.d.ts.map +1 -0
- package/dist/shaping/structured.js +115 -0
- package/dist/shaping/structured.js.map +1 -0
- package/dist/storage.d.ts +36 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +86 -0
- package/dist/storage.js.map +1 -0
- package/dist/transcribe-stream.d.ts +81 -0
- package/dist/transcribe-stream.d.ts.map +1 -0
- package/dist/transcribe-stream.js +253 -0
- package/dist/transcribe-stream.js.map +1 -0
- package/dist/transcribe.d.ts +57 -0
- package/dist/transcribe.d.ts.map +1 -0
- package/dist/transcribe.js +267 -0
- package/dist/transcribe.js.map +1 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machinery shared by the two room transports — the WebSocket ({@link ./transport.RoomSocket})
|
|
3
|
+
* and the SSE-receive stream ({@link ./sse.RoomEventStream}). Their reconnect *state machines* stay
|
|
4
|
+
* distinct (WS reconnects via a scheduled timer, SSE via an in-loop backoff), but the genuinely
|
|
5
|
+
* common parts — the reconnect/timeout constants, the exponential-backoff formula, and the
|
|
6
|
+
* ``connect()`` ready-waiter bookkeeping — live here so they can't drift apart.
|
|
7
|
+
*/
|
|
8
|
+
/** Backoff floor / ceiling (ms) and the ``connect()`` readiness budget — one source of truth for both
|
|
9
|
+
* transports (they were duplicated constants before). */
|
|
10
|
+
export declare const RECONNECT_MIN_MS = 500;
|
|
11
|
+
export declare const RECONNECT_MAX_MS = 5000;
|
|
12
|
+
export declare const CONNECT_TIMEOUT_MS = 30000;
|
|
13
|
+
/** The exponential-backoff delay for the ``attempt``-th reconnect (0-based), capped at
|
|
14
|
+
* {@link RECONNECT_MAX_MS}. */
|
|
15
|
+
export declare function backoffDelay(attempt: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* The ``connect()`` ready-waiter set both transports keep: each pending ``connect()`` pushes a
|
|
18
|
+
* ``{resolve, reject}`` pair; the first ``ready`` frame resolves them all, a terminal end / timeout
|
|
19
|
+
* rejects them all. Draining-then-firing (swap the list out before invoking) keeps a re-entrant
|
|
20
|
+
* ``connect()`` from a callback safe.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ReadyWaiters {
|
|
23
|
+
private waiters;
|
|
24
|
+
add(resolve: () => void, reject: (e: Error) => void): void;
|
|
25
|
+
resolveAll(): void;
|
|
26
|
+
rejectAll(error: Error): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=transport-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-shared.d.ts","sourceRoot":"","sources":["../../src/rooms/transport-shared.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;yDACyD;AACzD,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,gBAAgB,OAAO,CAAA;AACpC,eAAO,MAAM,kBAAkB,QAAS,CAAA;AAExC;+BAC+B;AAC/B,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAiE;IAEhF,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAI1D,UAAU,IAAI,IAAI;IAMlB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAK9B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machinery shared by the two room transports — the WebSocket ({@link ./transport.RoomSocket})
|
|
3
|
+
* and the SSE-receive stream ({@link ./sse.RoomEventStream}). Their reconnect *state machines* stay
|
|
4
|
+
* distinct (WS reconnects via a scheduled timer, SSE via an in-loop backoff), but the genuinely
|
|
5
|
+
* common parts — the reconnect/timeout constants, the exponential-backoff formula, and the
|
|
6
|
+
* ``connect()`` ready-waiter bookkeeping — live here so they can't drift apart.
|
|
7
|
+
*/
|
|
8
|
+
/** Backoff floor / ceiling (ms) and the ``connect()`` readiness budget — one source of truth for both
|
|
9
|
+
* transports (they were duplicated constants before). */
|
|
10
|
+
export const RECONNECT_MIN_MS = 500;
|
|
11
|
+
export const RECONNECT_MAX_MS = 5000;
|
|
12
|
+
export const CONNECT_TIMEOUT_MS = 30_000;
|
|
13
|
+
/** The exponential-backoff delay for the ``attempt``-th reconnect (0-based), capped at
|
|
14
|
+
* {@link RECONNECT_MAX_MS}. */
|
|
15
|
+
export function backoffDelay(attempt) {
|
|
16
|
+
return Math.min(RECONNECT_MIN_MS * 2 ** attempt, RECONNECT_MAX_MS);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The ``connect()`` ready-waiter set both transports keep: each pending ``connect()`` pushes a
|
|
20
|
+
* ``{resolve, reject}`` pair; the first ``ready`` frame resolves them all, a terminal end / timeout
|
|
21
|
+
* rejects them all. Draining-then-firing (swap the list out before invoking) keeps a re-entrant
|
|
22
|
+
* ``connect()`` from a callback safe.
|
|
23
|
+
*/
|
|
24
|
+
export class ReadyWaiters {
|
|
25
|
+
waiters = [];
|
|
26
|
+
add(resolve, reject) {
|
|
27
|
+
this.waiters.push({ resolve, reject });
|
|
28
|
+
}
|
|
29
|
+
resolveAll() {
|
|
30
|
+
const waiters = this.waiters;
|
|
31
|
+
this.waiters = [];
|
|
32
|
+
for (const w of waiters)
|
|
33
|
+
w.resolve();
|
|
34
|
+
}
|
|
35
|
+
rejectAll(error) {
|
|
36
|
+
const waiters = this.waiters;
|
|
37
|
+
this.waiters = [];
|
|
38
|
+
for (const w of waiters)
|
|
39
|
+
w.reject(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=transport-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-shared.js","sourceRoot":"","sources":["../../src/rooms/transport-shared.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;yDACyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAA;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAExC;+BAC+B;AAC/B,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,CAAC,IAAI,OAAO,EAAE,gBAAgB,CAAC,CAAA;AACpE,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IACf,OAAO,GAA+D,EAAE,CAAA;IAEhF,GAAG,CAAC,OAAmB,EAAE,MAA0B;QACjD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;IACxC,CAAC;IAED,UAAU;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,CAAC,CAAC,OAAO,EAAE,CAAA;IACtC,CAAC;IAED,SAAS,CAAC,KAAY;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The room's live WebSocket transport — extracted from the Player/tools client
|
|
3
|
+
* (``tools/src/lib/room-ws.ts``) and reshaped for the SDK. One socket carries both text signals
|
|
4
|
+
* (JSON) and the ephemeral binary audio stream, matching the server's ``/v1/rooms/{id}/ws`` route.
|
|
5
|
+
*
|
|
6
|
+
* Wire contract (server ``src/atrium/sessions/router.py``):
|
|
7
|
+
* • connect: ``ws(s)://…/v1/rooms/{id}/ws?code=…&identity=…&announce={json}`` (code-auth only —
|
|
8
|
+
* the WS route authorizes by connect code, never a bearer, so a host uses its own room's code).
|
|
9
|
+
* • inbound (server→client): ``{"kind":"ready", connection_id, participants}`` then
|
|
10
|
+
* ``{"kind":"signal", signal}`` text frames + raw binary frames; ``{"kind":"error", detail}`` on
|
|
11
|
+
* a rejected send.
|
|
12
|
+
* • outbound (client→server): ``{"kind":"signal", type, payload, to?, include_self?, source?,
|
|
13
|
+
* ack_id?, reply_to?}`` text frames; a raw binary frame broadcasts ephemerally to the room's
|
|
14
|
+
* other subscribers (the sender excluded). The server stamps ``from`` and owns ``connection_id``;
|
|
15
|
+
* everything a room carries is ephemeral (durable capture is a session's job).
|
|
16
|
+
*
|
|
17
|
+
* Unlike the tools copy this takes an already-resolved ``roomId`` (the Room resolved the code) and an
|
|
18
|
+
* injectable ``WebSocket`` constructor so the dispatch/correlation layer can be unit-tested against a
|
|
19
|
+
* scripted fake socket.
|
|
20
|
+
*/
|
|
21
|
+
/** An inbound room signal (``item.signal`` from the server), snake_case as the server serializes it. */
|
|
22
|
+
export interface RoomSignal {
|
|
23
|
+
type?: string;
|
|
24
|
+
payload?: unknown;
|
|
25
|
+
source?: string | null;
|
|
26
|
+
from?: string | null;
|
|
27
|
+
to?: string | string[] | null;
|
|
28
|
+
ack_id?: string | null;
|
|
29
|
+
reply_to?: string | null;
|
|
30
|
+
ephemeral?: boolean;
|
|
31
|
+
origin?: string;
|
|
32
|
+
}
|
|
33
|
+
/** The wire body of an outbound ``{"kind":"signal", …}`` frame (fields the server's WS recv reads). */
|
|
34
|
+
export interface OutboundSignal {
|
|
35
|
+
type: string;
|
|
36
|
+
payload?: unknown;
|
|
37
|
+
to?: string | string[];
|
|
38
|
+
includeSelf?: boolean;
|
|
39
|
+
source?: string;
|
|
40
|
+
ackId?: string;
|
|
41
|
+
replyTo?: string;
|
|
42
|
+
}
|
|
43
|
+
/** A live room roster entry — the raw item ``room.presence`` yields, as carried in the ``ready``
|
|
44
|
+
* snapshot and ``presence.join`` payloads. The parsed, query-friendly view (``name`` / merged
|
|
45
|
+
* ``roles`` / ``connectedAt`` as a ``Date``) is {@link ./participant.Participant}, behind
|
|
46
|
+
* ``room.participants()`` / ``room.has()``. */
|
|
47
|
+
export interface RosterEntry {
|
|
48
|
+
connectionId: string;
|
|
49
|
+
identity?: string | null;
|
|
50
|
+
announce?: Record<string, unknown>;
|
|
51
|
+
/** When this connection joined (ISO 8601). With eternal connections, apps that care can tell a
|
|
52
|
+
* fresh joiner from a week-old tab; most won't need it. */
|
|
53
|
+
connectedAt?: string | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The transport contract shared by the WebSocket ({@link RoomSocket}) and the SSE-receive +
|
|
57
|
+
* POST-send ({@link ./sse.RoomEventStream}) room channels — the two interchangeable ways a
|
|
58
|
+
* {@link ./room.Room} carries text signals. WS also carries the ephemeral binary audio stream; SSE
|
|
59
|
+
* is signals-only (``sendBinary`` is a no-op there — audio consumers stay WS-only).
|
|
60
|
+
*/
|
|
61
|
+
export interface RoomTransport {
|
|
62
|
+
connect(): Promise<void>;
|
|
63
|
+
sendSignal(sig: OutboundSignal): void;
|
|
64
|
+
sendBinary(data: ArrayBuffer): void;
|
|
65
|
+
close(): void;
|
|
66
|
+
connectionId(): string | null;
|
|
67
|
+
participants(): RosterEntry[];
|
|
68
|
+
}
|
|
69
|
+
/** The minimal ``WebSocket`` surface the transport uses — the browser/Node global satisfies it, and a
|
|
70
|
+
* test can supply a scripted fake. */
|
|
71
|
+
export interface WebSocketLike {
|
|
72
|
+
binaryType: string;
|
|
73
|
+
readyState: number;
|
|
74
|
+
send(data: string | ArrayBufferLike | ArrayBufferView): void;
|
|
75
|
+
close(code?: number, reason?: string): void;
|
|
76
|
+
onopen: ((ev: unknown) => void) | null;
|
|
77
|
+
onclose: ((ev: unknown) => void) | null;
|
|
78
|
+
onerror: ((ev: unknown) => void) | null;
|
|
79
|
+
onmessage: ((ev: {
|
|
80
|
+
data: unknown;
|
|
81
|
+
}) => void) | null;
|
|
82
|
+
}
|
|
83
|
+
export type WebSocketCtor = new (url: string) => WebSocketLike;
|
|
84
|
+
/** Why a room connection ended for good — no reconnect recovers. */
|
|
85
|
+
export type RoomEndReason = "code-rotated" | "bad-code" | "room-gone";
|
|
86
|
+
export interface RoomSocketHandlers {
|
|
87
|
+
/** An inbound text signal (already parsed from the ``{"kind":"signal"}`` envelope). May return a
|
|
88
|
+
* promise — the SSE transport **awaits** it inline in its read loop, so a consumer (the recorder)
|
|
89
|
+
* gets Python-style backpressure: the next frame isn't read until this settles. A rejection there
|
|
90
|
+
* is treated as a transient stream drop (backoff + reconnect). The WS transport ignores the return
|
|
91
|
+
* (its consumers are synchronous). */
|
|
92
|
+
onSignal?: (signal: RoomSignal) => void | Promise<void>;
|
|
93
|
+
/** A raw inbound binary frame (the audio stream). */
|
|
94
|
+
onBinary?: (data: ArrayBuffer) => void;
|
|
95
|
+
/** Every (re)open, with the freshly minted connection id — re-send anything the room needs. */
|
|
96
|
+
onReady?: (connectionId: string) => void;
|
|
97
|
+
/** The roster changed (seeded from ``ready``, updated by presence deltas; excludes self). */
|
|
98
|
+
onParticipants?: (participants: RosterEntry[]) => void;
|
|
99
|
+
/** A server ``{"kind":"error"}`` frame (reserved type, oversized binary, …). */
|
|
100
|
+
onError?: (detail: string) => void;
|
|
101
|
+
/** A terminal, identifiable end (code rotated / bad / room gone) — the socket stops reconnecting. */
|
|
102
|
+
onEnd?: (reason: RoomEndReason) => void;
|
|
103
|
+
/** The socket failed to reach ``ready`` on its first attempt (a proxy stripping the WS upgrade
|
|
104
|
+
* looks like this) — the {@link ./room.Room} fallback probe switches to SSE. Set only when
|
|
105
|
+
* ``probe`` is true; when it fires the socket stops (no reconnect) and {@link connect} rejects. */
|
|
106
|
+
onUnavailable?: () => void;
|
|
107
|
+
}
|
|
108
|
+
export interface RoomSocketOptions extends RoomSocketHandlers {
|
|
109
|
+
roomId: string;
|
|
110
|
+
/** Connect code — the WS route's only auth. A host passes its own room's code. */
|
|
111
|
+
code: string;
|
|
112
|
+
/** The instance base URL (http/https); the socket derives ws/wss from it. */
|
|
113
|
+
baseUrl: string;
|
|
114
|
+
identity?: string;
|
|
115
|
+
announce?: Record<string, unknown>;
|
|
116
|
+
/** Reconnect on unexpected close (default true). */
|
|
117
|
+
reconnect?: boolean;
|
|
118
|
+
/** Probe mode: if the first connect fails before ``ready`` (non-terminal), fire
|
|
119
|
+
* {@link RoomSocketHandlers.onUnavailable} and stop instead of reconnecting — so the Room can
|
|
120
|
+
* fall back to SSE fast rather than hang the full connect timeout on a WS-stripping proxy. */
|
|
121
|
+
probe?: boolean;
|
|
122
|
+
/** Injected ``WebSocket`` constructor (defaults to the runtime global) — the test seam. */
|
|
123
|
+
WebSocketCtor?: WebSocketCtor;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A single logical room connection with transparent reconnect. {@link connect} resolves once the
|
|
127
|
+
* server's first ``ready`` frame arrives (so ``connectionId`` is known); after that, drops reconnect
|
|
128
|
+
* with backoff until {@link close}. Sends while the socket is momentarily down are dropped (rooms
|
|
129
|
+
* have no replay) — re-emit inside {@link RoomSocketHandlers.onReady} for reliability.
|
|
130
|
+
*/
|
|
131
|
+
export declare class RoomSocket implements RoomTransport {
|
|
132
|
+
private readonly opts;
|
|
133
|
+
private ws;
|
|
134
|
+
private connId;
|
|
135
|
+
private closed;
|
|
136
|
+
private attempt;
|
|
137
|
+
private retryTimer;
|
|
138
|
+
private roster;
|
|
139
|
+
private readonly readyWaiters;
|
|
140
|
+
private everReady;
|
|
141
|
+
private terminal;
|
|
142
|
+
private rotationSeen;
|
|
143
|
+
private readonly Ctor;
|
|
144
|
+
constructor(opts: RoomSocketOptions);
|
|
145
|
+
/** The current connection id, or ``null`` before the first ``ready``. */
|
|
146
|
+
connectionId(): string | null;
|
|
147
|
+
/** The current participant roster (excludes self), maintained from ``ready`` + presence deltas. */
|
|
148
|
+
participants(): RosterEntry[];
|
|
149
|
+
/** Open the socket and resolve once it's live (the server's ``ready`` frame arrived). Idempotent. */
|
|
150
|
+
connect(): Promise<void>;
|
|
151
|
+
/** Send a text signal. Dropped (no-op) while the socket is not open. */
|
|
152
|
+
sendSignal(sig: OutboundSignal): void;
|
|
153
|
+
/** Send a raw binary frame (ephemeral, broadcast to others). Dropped while not open. */
|
|
154
|
+
sendBinary(data: ArrayBuffer): void;
|
|
155
|
+
/** Close the socket and stop reconnecting (idempotent). */
|
|
156
|
+
close(): void;
|
|
157
|
+
private open;
|
|
158
|
+
private scheduleReconnect;
|
|
159
|
+
private updateRoster;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/rooms/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,wGAAwG;AACxG,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,uGAAuG;AACvG,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;+CAG+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC;+DAC2D;IAC3D,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAAA;IACrC,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IACnC,KAAK,IAAI,IAAI,CAAA;IACb,YAAY,IAAI,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,IAAI,WAAW,EAAE,CAAA;CAC9B;AAED;sCACsC;AACtC,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,eAAe,GAAG,IAAI,CAAA;IAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA;IACtC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA;IACvC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA;IACvC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA;CACpD;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,EAAE,MAAM,KAAK,aAAa,CAAA;AAW9D,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,CAAA;AAErE,MAAM,WAAW,kBAAkB;IACjC;;;;0CAIsC;IACtC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,qDAAqD;IACrD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,+FAA+F;IAC/F,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,6FAA6F;IAC7F,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,IAAI,CAAA;IACtD,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,qGAAqG;IACrG,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACvC;;uGAEmG;IACnG,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,MAAM,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAA;IACZ,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;kGAE8F;IAC9F,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,2FAA2F;IAC3F,aAAa,CAAC,EAAE,aAAa,CAAA;CAC9B;AAOD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,aAAa;IAgBlC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAfjC,OAAO,CAAC,EAAE,CAA6B;IACvC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,QAAQ,CAAQ;IAGxB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;gBAEP,IAAI,EAAE,iBAAiB;IAUpD,yEAAyE;IACzE,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,mGAAmG;IACnG,YAAY,IAAI,WAAW,EAAE;IAI7B,qGAAqG;IACrG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BxB,wEAAwE;IACxE,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAerC,wFAAwF;IACxF,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAKnC,2DAA2D;IAC3D,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,IAAI;IA2FZ,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,YAAY;CA6BrB"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The room's live WebSocket transport — extracted from the Player/tools client
|
|
3
|
+
* (``tools/src/lib/room-ws.ts``) and reshaped for the SDK. One socket carries both text signals
|
|
4
|
+
* (JSON) and the ephemeral binary audio stream, matching the server's ``/v1/rooms/{id}/ws`` route.
|
|
5
|
+
*
|
|
6
|
+
* Wire contract (server ``src/atrium/sessions/router.py``):
|
|
7
|
+
* • connect: ``ws(s)://…/v1/rooms/{id}/ws?code=…&identity=…&announce={json}`` (code-auth only —
|
|
8
|
+
* the WS route authorizes by connect code, never a bearer, so a host uses its own room's code).
|
|
9
|
+
* • inbound (server→client): ``{"kind":"ready", connection_id, participants}`` then
|
|
10
|
+
* ``{"kind":"signal", signal}`` text frames + raw binary frames; ``{"kind":"error", detail}`` on
|
|
11
|
+
* a rejected send.
|
|
12
|
+
* • outbound (client→server): ``{"kind":"signal", type, payload, to?, include_self?, source?,
|
|
13
|
+
* ack_id?, reply_to?}`` text frames; a raw binary frame broadcasts ephemerally to the room's
|
|
14
|
+
* other subscribers (the sender excluded). The server stamps ``from`` and owns ``connection_id``;
|
|
15
|
+
* everything a room carries is ephemeral (durable capture is a session's job).
|
|
16
|
+
*
|
|
17
|
+
* Unlike the tools copy this takes an already-resolved ``roomId`` (the Room resolved the code) and an
|
|
18
|
+
* injectable ``WebSocket`` constructor so the dispatch/correlation layer can be unit-tested against a
|
|
19
|
+
* scripted fake socket.
|
|
20
|
+
*/
|
|
21
|
+
import { backoffDelay, CONNECT_TIMEOUT_MS, ReadyWaiters } from "./transport-shared.js";
|
|
22
|
+
const WS_OPEN = 1; // WebSocket.OPEN — hardcoded so we don't touch a possibly-absent global constant.
|
|
23
|
+
// Terminal WS close codes the server uses for a connection it will never welcome back on this code —
|
|
24
|
+
// no reconnect recovers, so we stop and surface *why* (mirror of the tools ``room-ws.ts`` client).
|
|
25
|
+
// An endless retry loop on a dead code would otherwise hammer the server's per-IP attempt limiter.
|
|
26
|
+
const CLOSE_CODE_ROTATED = 4410; // the connect code was rotated (advance-signalled by room.code_rotated)
|
|
27
|
+
const CLOSE_BAD_CODE = 4403; // the connect code was rejected (bad/expired)
|
|
28
|
+
const CLOSE_ROOM_GONE = 4404; // the room no longer exists
|
|
29
|
+
function wsUrl(baseUrl, roomId, params) {
|
|
30
|
+
const base = baseUrl.replace(/^http/, "ws").replace(/\/+$/, "");
|
|
31
|
+
return `${base}/v1/rooms/${roomId}/ws?${params.toString()}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A single logical room connection with transparent reconnect. {@link connect} resolves once the
|
|
35
|
+
* server's first ``ready`` frame arrives (so ``connectionId`` is known); after that, drops reconnect
|
|
36
|
+
* with backoff until {@link close}. Sends while the socket is momentarily down are dropped (rooms
|
|
37
|
+
* have no replay) — re-emit inside {@link RoomSocketHandlers.onReady} for reliability.
|
|
38
|
+
*/
|
|
39
|
+
export class RoomSocket {
|
|
40
|
+
opts;
|
|
41
|
+
ws = null;
|
|
42
|
+
connId = null;
|
|
43
|
+
closed = false;
|
|
44
|
+
attempt = 0;
|
|
45
|
+
retryTimer = null;
|
|
46
|
+
roster = [];
|
|
47
|
+
readyWaiters = new ReadyWaiters();
|
|
48
|
+
everReady = false;
|
|
49
|
+
// A terminal failure (rotated / bad / gone code) was seen — never reconnect again.
|
|
50
|
+
terminal = false;
|
|
51
|
+
// A room.code_rotated signal arrived — classify the following close as rotation even if its 4410
|
|
52
|
+
// close code is lost in transit.
|
|
53
|
+
rotationSeen = false;
|
|
54
|
+
Ctor;
|
|
55
|
+
constructor(opts) {
|
|
56
|
+
this.opts = opts;
|
|
57
|
+
const Ctor = opts.WebSocketCtor ?? globalThis.WebSocket;
|
|
58
|
+
if (!Ctor) {
|
|
59
|
+
throw new Error("Atrium rooms: no WebSocket implementation — pass { WebSocketCtor } (Node <22 has none global)");
|
|
60
|
+
}
|
|
61
|
+
this.Ctor = Ctor;
|
|
62
|
+
}
|
|
63
|
+
/** The current connection id, or ``null`` before the first ``ready``. */
|
|
64
|
+
connectionId() {
|
|
65
|
+
return this.connId;
|
|
66
|
+
}
|
|
67
|
+
/** The current participant roster (excludes self), maintained from ``ready`` + presence deltas. */
|
|
68
|
+
participants() {
|
|
69
|
+
return [...this.roster];
|
|
70
|
+
}
|
|
71
|
+
/** Open the socket and resolve once it's live (the server's ``ready`` frame arrived). Idempotent. */
|
|
72
|
+
connect() {
|
|
73
|
+
if (this.everReady && this.ws)
|
|
74
|
+
return Promise.resolve();
|
|
75
|
+
// A closed socket never reopens — reject at once rather than call ``open()`` (which early-returns
|
|
76
|
+
// on ``closed`` without resolving a waiter, hanging the full CONNECT_TIMEOUT). This is the
|
|
77
|
+
// connect-after-close race: an abort fired ``close()`` just before a consumer awaits ``connect()``.
|
|
78
|
+
if (this.closed)
|
|
79
|
+
return Promise.reject(new Error("room closed"));
|
|
80
|
+
const promise = new Promise((resolve, reject) => {
|
|
81
|
+
this.readyWaiters.add(resolve, reject);
|
|
82
|
+
});
|
|
83
|
+
if (!this.ws) {
|
|
84
|
+
// A drop may have scheduled a reconnect; clear it so we don't open a second socket (this
|
|
85
|
+
// manual open supersedes the pending retry).
|
|
86
|
+
if (this.retryTimer) {
|
|
87
|
+
clearTimeout(this.retryTimer);
|
|
88
|
+
this.retryTimer = null;
|
|
89
|
+
}
|
|
90
|
+
this.open();
|
|
91
|
+
const timer = setTimeout(() => {
|
|
92
|
+
this.readyWaiters.rejectAll(new Error(`room stream not ready within ${CONNECT_TIMEOUT_MS / 1000}s`));
|
|
93
|
+
}, CONNECT_TIMEOUT_MS);
|
|
94
|
+
// Clear the timeout when the promise settles either way.
|
|
95
|
+
void promise.finally(() => clearTimeout(timer)).catch(() => { });
|
|
96
|
+
}
|
|
97
|
+
return promise;
|
|
98
|
+
}
|
|
99
|
+
/** Send a text signal. Dropped (no-op) while the socket is not open. */
|
|
100
|
+
sendSignal(sig) {
|
|
101
|
+
if (!this.ws || this.ws.readyState !== WS_OPEN)
|
|
102
|
+
return;
|
|
103
|
+
const frame = {
|
|
104
|
+
kind: "signal",
|
|
105
|
+
type: sig.type,
|
|
106
|
+
payload: sig.payload ?? {},
|
|
107
|
+
};
|
|
108
|
+
if (sig.to !== undefined)
|
|
109
|
+
frame.to = sig.to;
|
|
110
|
+
if (sig.includeSelf)
|
|
111
|
+
frame.include_self = true;
|
|
112
|
+
if (sig.source !== undefined)
|
|
113
|
+
frame.source = sig.source;
|
|
114
|
+
if (sig.ackId !== undefined)
|
|
115
|
+
frame.ack_id = sig.ackId;
|
|
116
|
+
if (sig.replyTo !== undefined)
|
|
117
|
+
frame.reply_to = sig.replyTo;
|
|
118
|
+
this.ws.send(JSON.stringify(frame));
|
|
119
|
+
}
|
|
120
|
+
/** Send a raw binary frame (ephemeral, broadcast to others). Dropped while not open. */
|
|
121
|
+
sendBinary(data) {
|
|
122
|
+
if (!this.ws || this.ws.readyState !== WS_OPEN)
|
|
123
|
+
return;
|
|
124
|
+
this.ws.send(data);
|
|
125
|
+
}
|
|
126
|
+
/** Close the socket and stop reconnecting (idempotent). */
|
|
127
|
+
close() {
|
|
128
|
+
this.closed = true;
|
|
129
|
+
if (this.retryTimer)
|
|
130
|
+
clearTimeout(this.retryTimer);
|
|
131
|
+
this.retryTimer = null;
|
|
132
|
+
this.ws?.close();
|
|
133
|
+
this.ws = null;
|
|
134
|
+
this.readyWaiters.rejectAll(new Error("room closed"));
|
|
135
|
+
}
|
|
136
|
+
open() {
|
|
137
|
+
if (this.closed)
|
|
138
|
+
return;
|
|
139
|
+
const params = new URLSearchParams({ code: this.opts.code });
|
|
140
|
+
if (this.opts.identity)
|
|
141
|
+
params.set("identity", this.opts.identity);
|
|
142
|
+
if (this.opts.announce)
|
|
143
|
+
params.set("announce", JSON.stringify(this.opts.announce));
|
|
144
|
+
const sock = new this.Ctor(wsUrl(this.opts.baseUrl, this.opts.roomId, params));
|
|
145
|
+
sock.binaryType = "arraybuffer";
|
|
146
|
+
this.ws = sock;
|
|
147
|
+
sock.onmessage = (ev) => {
|
|
148
|
+
if (typeof ev.data !== "string") {
|
|
149
|
+
this.opts.onBinary?.(ev.data);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
let msg;
|
|
153
|
+
try {
|
|
154
|
+
msg = JSON.parse(ev.data);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (msg.kind === "ready") {
|
|
160
|
+
this.connId = msg.connection_id ?? null;
|
|
161
|
+
this.attempt = 0;
|
|
162
|
+
this.everReady = true;
|
|
163
|
+
this.roster = (msg.participants ?? []).map((p) => ({
|
|
164
|
+
connectionId: p.connection_id,
|
|
165
|
+
identity: p.identity,
|
|
166
|
+
announce: p.announce,
|
|
167
|
+
connectedAt: p.connected_at,
|
|
168
|
+
}));
|
|
169
|
+
this.opts.onParticipants?.(this.participants());
|
|
170
|
+
this.readyWaiters.resolveAll();
|
|
171
|
+
if (this.connId)
|
|
172
|
+
this.opts.onReady?.(this.connId);
|
|
173
|
+
}
|
|
174
|
+
else if (msg.kind === "signal" && msg.signal) {
|
|
175
|
+
// Advance notice of an imminent code rotation — mark it so the following close is classified
|
|
176
|
+
// as a rotation even if the 4410 close code is lost.
|
|
177
|
+
if (msg.signal.type === "room.code_rotated")
|
|
178
|
+
this.rotationSeen = true;
|
|
179
|
+
this.updateRoster(msg.signal);
|
|
180
|
+
this.opts.onSignal?.(msg.signal);
|
|
181
|
+
}
|
|
182
|
+
else if (msg.kind === "error") {
|
|
183
|
+
this.opts.onError?.(msg.detail ?? "error");
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
sock.onclose = (ev) => {
|
|
187
|
+
if (this.ws === sock)
|
|
188
|
+
this.ws = null;
|
|
189
|
+
if (this.closed)
|
|
190
|
+
return;
|
|
191
|
+
const code = ev?.code;
|
|
192
|
+
const reason = code === CLOSE_CODE_ROTATED || this.rotationSeen
|
|
193
|
+
? "code-rotated"
|
|
194
|
+
: code === CLOSE_BAD_CODE
|
|
195
|
+
? "bad-code"
|
|
196
|
+
: code === CLOSE_ROOM_GONE
|
|
197
|
+
? "room-gone"
|
|
198
|
+
: null;
|
|
199
|
+
if (reason) {
|
|
200
|
+
// Terminal: stop reconnecting for good and surface the reason. A pending connect() that never
|
|
201
|
+
// reached `ready` rejects identifiably; a live handle learns via onEnd.
|
|
202
|
+
this.terminal = true;
|
|
203
|
+
if (!this.everReady)
|
|
204
|
+
this.readyWaiters.rejectAll(new Error(`room connection ended: ${reason}`));
|
|
205
|
+
this.opts.onEnd?.(reason);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (this.opts.probe && !this.everReady) {
|
|
209
|
+
// The WS never came up on the fallback probe (a proxy stripping the upgrade looks exactly
|
|
210
|
+
// like this — an abnormal close before ready). Don't retry: signal unavailability so the Room
|
|
211
|
+
// switches to SSE, and reject the pending connect rather than hang the full connect timeout.
|
|
212
|
+
this.terminal = true;
|
|
213
|
+
this.opts.onUnavailable?.();
|
|
214
|
+
this.readyWaiters.rejectAll(new Error("room websocket unavailable"));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.scheduleReconnect();
|
|
218
|
+
};
|
|
219
|
+
// onerror is followed by onclose; let onclose drive the retry so we don't double-schedule.
|
|
220
|
+
sock.onerror = () => { };
|
|
221
|
+
}
|
|
222
|
+
scheduleReconnect() {
|
|
223
|
+
if (this.closed || this.terminal || this.opts.reconnect === false) {
|
|
224
|
+
// No reconnect and never became ready → fail any pending connect().
|
|
225
|
+
if (!this.everReady)
|
|
226
|
+
this.readyWaiters.rejectAll(new Error("room connection closed before ready"));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const delay = backoffDelay(this.attempt);
|
|
230
|
+
this.attempt += 1;
|
|
231
|
+
this.retryTimer = setTimeout(() => this.open(), delay);
|
|
232
|
+
}
|
|
233
|
+
// Apply a presence delta to the roster (dedupe by connection id; tolerate unknown leaves).
|
|
234
|
+
updateRoster(sig) {
|
|
235
|
+
const p = sig.payload;
|
|
236
|
+
if (sig.type === "presence.join") {
|
|
237
|
+
if (p?.connection_id && !this.roster.some((x) => x.connectionId === p.connection_id)) {
|
|
238
|
+
this.roster = [
|
|
239
|
+
...this.roster,
|
|
240
|
+
{
|
|
241
|
+
connectionId: p.connection_id,
|
|
242
|
+
identity: p.identity,
|
|
243
|
+
announce: p.announce,
|
|
244
|
+
connectedAt: p.connected_at,
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
this.opts.onParticipants?.(this.participants());
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (sig.type === "presence.leave") {
|
|
251
|
+
if (p?.connection_id && this.roster.some((x) => x.connectionId === p.connection_id)) {
|
|
252
|
+
this.roster = this.roster.filter((x) => x.connectionId !== p.connection_id);
|
|
253
|
+
this.opts.onParticipants?.(this.participants());
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/rooms/transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Asset list / get / upload request shaping (mirror of ``_shaping`` asset helpers). */
|
|
2
|
+
import type { FileSource } from "../files.js";
|
|
3
|
+
import { type ShapedRequest } from "./request.js";
|
|
4
|
+
export interface BuildAssetListInput {
|
|
5
|
+
modality?: string;
|
|
6
|
+
contentKind?: string[];
|
|
7
|
+
limit: number;
|
|
8
|
+
cursor?: string;
|
|
9
|
+
project?: string;
|
|
10
|
+
collection?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Build a ``GET /v1/assets`` listing request. The scope is already resolved. */
|
|
13
|
+
export declare function buildAssetList(input: BuildAssetListInput): ShapedRequest;
|
|
14
|
+
/** Build a ``GET /v1/assets/{id}`` request. ``collection`` is already resolved. */
|
|
15
|
+
export declare function buildAssetGet(assetId: string, opts?: {
|
|
16
|
+
collection?: string;
|
|
17
|
+
}): ShapedRequest;
|
|
18
|
+
export interface BuildUploadInput {
|
|
19
|
+
file: FileSource;
|
|
20
|
+
modality?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
collection?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Build a ``GET /v1/assets/{id}/vectors`` request (public by-id). ``space`` (one or a list) is
|
|
25
|
+
* already resolved; a list rides as repeated ``space=`` query params. */
|
|
26
|
+
export declare function buildAssetVectors(assetId: string, opts?: {
|
|
27
|
+
space?: string | string[];
|
|
28
|
+
matchBy?: string;
|
|
29
|
+
}): ShapedRequest;
|
|
30
|
+
/** Build a ``GET /v1/assets/{id}/segments`` request (public by-id). */
|
|
31
|
+
export declare function buildAssetSegments(assetId: string): ShapedRequest;
|
|
32
|
+
/** Build a ``GET /v1/assets/{id}/index`` request (authenticated, visibility-scoped). */
|
|
33
|
+
export declare function buildAssetIndex(assetId: string): ShapedRequest;
|
|
34
|
+
/** Build a ``POST /v1/library/vectors`` bulk request. ``space`` (one or a list) is already
|
|
35
|
+
* resolved. */
|
|
36
|
+
export declare function buildBulkVectors(ids: string[], input: {
|
|
37
|
+
space: string | string[];
|
|
38
|
+
matchBy?: string;
|
|
39
|
+
}): ShapedRequest;
|
|
40
|
+
/** Build a ``POST /v1/assets`` upload request. ``collection`` is already resolved. */
|
|
41
|
+
export declare function buildUpload(input: BuildUploadInput): ShapedRequest;
|
|
42
|
+
//# sourceMappingURL=assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/shaping/assets.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAE7D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,aAAa,CAaxE;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,aAAa,CAMhG;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;yEACyE;AACzE,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,aAAa,CAaf;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAEjE;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAE9D;AAED;eACe;AACf,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EAAE,EACb,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,aAAa,CAMf;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,aAAa,CAgBlE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Asset list / get / upload request shaping (mirror of ``_shaping`` asset helpers). */
|
|
2
|
+
import { applyScope } from "./request.js";
|
|
3
|
+
/** Build a ``GET /v1/assets`` listing request. The scope is already resolved. */
|
|
4
|
+
export function buildAssetList(input) {
|
|
5
|
+
const query = { limit: input.limit };
|
|
6
|
+
if (input.cursor !== undefined) {
|
|
7
|
+
query.cursor = input.cursor;
|
|
8
|
+
}
|
|
9
|
+
if (input.modality !== undefined) {
|
|
10
|
+
query.all_kinds = [input.modality];
|
|
11
|
+
}
|
|
12
|
+
if (input.contentKind?.length) {
|
|
13
|
+
query.content_kind = input.contentKind;
|
|
14
|
+
}
|
|
15
|
+
applyScope(query, input.project, input.collection);
|
|
16
|
+
return { method: "GET", path: "/v1/assets", query };
|
|
17
|
+
}
|
|
18
|
+
/** Build a ``GET /v1/assets/{id}`` request. ``collection`` is already resolved. */
|
|
19
|
+
export function buildAssetGet(assetId, opts = {}) {
|
|
20
|
+
const req = { method: "GET", path: `/v1/assets/${assetId}` };
|
|
21
|
+
if (opts.collection !== undefined) {
|
|
22
|
+
req.query = { collection: opts.collection };
|
|
23
|
+
}
|
|
24
|
+
return req;
|
|
25
|
+
}
|
|
26
|
+
/** Build a ``GET /v1/assets/{id}/vectors`` request (public by-id). ``space`` (one or a list) is
|
|
27
|
+
* already resolved; a list rides as repeated ``space=`` query params. */
|
|
28
|
+
export function buildAssetVectors(assetId, opts = {}) {
|
|
29
|
+
const query = {};
|
|
30
|
+
if (opts.space !== undefined) {
|
|
31
|
+
query.space = opts.space;
|
|
32
|
+
}
|
|
33
|
+
if (opts.matchBy !== undefined) {
|
|
34
|
+
query.match_by = opts.matchBy;
|
|
35
|
+
}
|
|
36
|
+
const req = { method: "GET", path: `/v1/assets/${assetId}/vectors` };
|
|
37
|
+
if (Object.keys(query).length) {
|
|
38
|
+
req.query = query;
|
|
39
|
+
}
|
|
40
|
+
return req;
|
|
41
|
+
}
|
|
42
|
+
/** Build a ``GET /v1/assets/{id}/segments`` request (public by-id). */
|
|
43
|
+
export function buildAssetSegments(assetId) {
|
|
44
|
+
return { method: "GET", path: `/v1/assets/${assetId}/segments` };
|
|
45
|
+
}
|
|
46
|
+
/** Build a ``GET /v1/assets/{id}/index`` request (authenticated, visibility-scoped). */
|
|
47
|
+
export function buildAssetIndex(assetId) {
|
|
48
|
+
return { method: "GET", path: `/v1/assets/${assetId}/index` };
|
|
49
|
+
}
|
|
50
|
+
/** Build a ``POST /v1/library/vectors`` bulk request. ``space`` (one or a list) is already
|
|
51
|
+
* resolved. */
|
|
52
|
+
export function buildBulkVectors(ids, input) {
|
|
53
|
+
const body = { ids, space: input.space };
|
|
54
|
+
if (input.matchBy !== undefined) {
|
|
55
|
+
body.match_by = input.matchBy;
|
|
56
|
+
}
|
|
57
|
+
return { method: "POST", path: "/v1/library/vectors", json: body };
|
|
58
|
+
}
|
|
59
|
+
/** Build a ``POST /v1/assets`` upload request. ``collection`` is already resolved. */
|
|
60
|
+
export function buildUpload(input) {
|
|
61
|
+
const fields = {};
|
|
62
|
+
if (input.modality !== undefined) {
|
|
63
|
+
fields.modality = input.modality;
|
|
64
|
+
}
|
|
65
|
+
if (input.description !== undefined) {
|
|
66
|
+
fields.description = input.description;
|
|
67
|
+
}
|
|
68
|
+
if (input.collection !== undefined) {
|
|
69
|
+
fields.collection = input.collection;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
method: "POST",
|
|
73
|
+
path: "/v1/assets",
|
|
74
|
+
multipart: { fields, files: { file: { source: input.file } } },
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=assets.js.map
|