@soulcraft/sdk 1.0.0 → 1.2.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/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/auth/service-token.d.ts +62 -0
- package/dist/modules/auth/service-token.d.ts.map +1 -0
- package/dist/modules/auth/service-token.js +99 -0
- package/dist/modules/auth/service-token.js.map +1 -0
- package/dist/modules/billing/firestore-provider.d.ts +60 -0
- package/dist/modules/billing/firestore-provider.d.ts.map +1 -0
- package/dist/modules/billing/firestore-provider.js +314 -0
- package/dist/modules/billing/firestore-provider.js.map +1 -0
- package/dist/modules/billing/index.d.ts +58 -0
- package/dist/modules/billing/index.d.ts.map +1 -0
- package/dist/modules/billing/index.js +164 -0
- package/dist/modules/billing/index.js.map +1 -0
- package/dist/modules/billing/local-provider.d.ts +38 -0
- package/dist/modules/billing/local-provider.d.ts.map +1 -0
- package/dist/modules/billing/local-provider.js +242 -0
- package/dist/modules/billing/local-provider.js.map +1 -0
- package/dist/modules/billing/portal-provider.d.ts +70 -0
- package/dist/modules/billing/portal-provider.d.ts.map +1 -0
- package/dist/modules/billing/portal-provider.js +204 -0
- package/dist/modules/billing/portal-provider.js.map +1 -0
- package/dist/modules/billing/types.d.ts +323 -3
- package/dist/modules/billing/types.d.ts.map +1 -1
- package/dist/modules/billing/types.js +22 -2
- package/dist/modules/billing/types.js.map +1 -1
- package/dist/modules/billing/usage-buffer.d.ts +72 -0
- package/dist/modules/billing/usage-buffer.d.ts.map +1 -0
- package/dist/modules/billing/usage-buffer.js +141 -0
- package/dist/modules/billing/usage-buffer.js.map +1 -0
- package/dist/modules/formats/types.d.ts +65 -3
- package/dist/modules/formats/types.d.ts.map +1 -1
- package/dist/modules/formats/types.js +40 -3
- package/dist/modules/formats/types.js.map +1 -1
- package/dist/modules/formats/wdoc.d.ts +263 -0
- package/dist/modules/formats/wdoc.d.ts.map +1 -0
- package/dist/modules/formats/wdoc.js +21 -0
- package/dist/modules/formats/wdoc.js.map +1 -0
- package/dist/modules/formats/wquiz.d.ts +122 -0
- package/dist/modules/formats/wquiz.d.ts.map +1 -0
- package/dist/modules/formats/wquiz.js +23 -0
- package/dist/modules/formats/wquiz.js.map +1 -0
- package/dist/modules/formats/wslide.d.ts +130 -0
- package/dist/modules/formats/wslide.d.ts.map +1 -0
- package/dist/modules/formats/wslide.js +23 -0
- package/dist/modules/formats/wslide.js.map +1 -0
- package/dist/modules/formats/wviz.d.ts +114 -0
- package/dist/modules/formats/wviz.d.ts.map +1 -0
- package/dist/modules/formats/wviz.js +21 -0
- package/dist/modules/formats/wviz.js.map +1 -0
- package/dist/modules/hall/browser.d.ts +88 -0
- package/dist/modules/hall/browser.d.ts.map +1 -0
- package/dist/modules/hall/browser.js +265 -0
- package/dist/modules/hall/browser.js.map +1 -0
- package/dist/modules/hall/protocol.d.ts +39 -0
- package/dist/modules/hall/protocol.d.ts.map +1 -0
- package/dist/modules/hall/protocol.js +52 -0
- package/dist/modules/hall/protocol.js.map +1 -0
- package/dist/modules/hall/server.d.ts +172 -0
- package/dist/modules/hall/server.d.ts.map +1 -0
- package/dist/modules/hall/server.js +457 -0
- package/dist/modules/hall/server.js.map +1 -0
- package/dist/modules/hall/types.d.ts +502 -31
- package/dist/modules/hall/types.d.ts.map +1 -1
- package/dist/modules/hall/types.js +13 -8
- package/dist/modules/hall/types.js.map +1 -1
- package/dist/modules/kits/index.d.ts +41 -0
- package/dist/modules/kits/index.d.ts.map +1 -0
- package/dist/modules/kits/index.js +85 -0
- package/dist/modules/kits/index.js.map +1 -0
- package/dist/modules/kits/types.d.ts +107 -3
- package/dist/modules/kits/types.d.ts.map +1 -1
- package/dist/modules/kits/types.js +15 -2
- package/dist/modules/kits/types.js.map +1 -1
- package/dist/modules/license/index.d.ts +53 -0
- package/dist/modules/license/index.d.ts.map +1 -0
- package/dist/modules/license/index.js +233 -0
- package/dist/modules/license/index.js.map +1 -0
- package/dist/modules/license/types.d.ts +222 -3
- package/dist/modules/license/types.d.ts.map +1 -1
- package/dist/modules/license/types.js +21 -2
- package/dist/modules/license/types.js.map +1 -1
- package/dist/modules/notifications/index.d.ts +40 -0
- package/dist/modules/notifications/index.d.ts.map +1 -0
- package/dist/modules/notifications/index.js +280 -0
- package/dist/modules/notifications/index.js.map +1 -0
- package/dist/modules/notifications/types.d.ts +152 -3
- package/dist/modules/notifications/types.d.ts.map +1 -1
- package/dist/modules/notifications/types.js +21 -2
- package/dist/modules/notifications/types.js.map +1 -1
- package/dist/server/create-sdk.d.ts +4 -0
- package/dist/server/create-sdk.d.ts.map +1 -1
- package/dist/server/create-sdk.js +19 -26
- package/dist/server/create-sdk.js.map +1 -1
- package/dist/server/hall-handlers.d.ts +90 -151
- package/dist/server/hall-handlers.d.ts.map +1 -1
- package/dist/server/hall-handlers.js +84 -204
- package/dist/server/hall-handlers.js.map +1 -1
- package/dist/server/index.d.ts +10 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +9 -2
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +35 -25
- package/dist/types.d.ts.map +1 -1
- package/docs/USAGE.md +224 -1
- package/package.json +13 -5
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/hall/server
|
|
3
|
+
* @description Server-side Hall client — product backend to Hall server control plane.
|
|
4
|
+
*
|
|
5
|
+
* `HallClient` maintains a single authenticated WebSocket connection from the product
|
|
6
|
+
* backend to `hall.soulcraft.com`. All room management (createRoom, closeRoom, session
|
|
7
|
+
* tokens, recording) goes through this connection.
|
|
8
|
+
*
|
|
9
|
+
* This module is **server-only** — it uses WebSocket, reconnect timers, and the
|
|
10
|
+
* product shared secret, none of which should ever reach a browser bundle.
|
|
11
|
+
*
|
|
12
|
+
* Use `createHallModule(options)` from `@soulcraft/sdk/server` to get a fully wired
|
|
13
|
+
* `HallModule` instance. Direct use of `HallClient` is for advanced scenarios.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { createHallModule } from '@soulcraft/sdk/server'
|
|
18
|
+
*
|
|
19
|
+
* const hall = createHallModule({
|
|
20
|
+
* url: process.env.HALL_URL!,
|
|
21
|
+
* productName: 'academy',
|
|
22
|
+
* secret: process.env.HALL_ACADEMY_SECRET!,
|
|
23
|
+
* })
|
|
24
|
+
* await hall.connect()
|
|
25
|
+
* const room = await hall.createRoom('cohort-123', { enableTranscription: true })
|
|
26
|
+
* room.on('transcript', (t) => console.log(t.text))
|
|
27
|
+
* const { token } = await hall.createSessionToken('cohort-123', 'user-456')
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import { encodeHallMessage, decodeHallMessage } from './protocol.js';
|
|
31
|
+
/**
|
|
32
|
+
* Concrete implementation of the {@link HallRoom} interface.
|
|
33
|
+
*
|
|
34
|
+
* Stores per-event listener sets and provides a typed dispatch method called
|
|
35
|
+
* internally by `HallClient` when the server pushes room events.
|
|
36
|
+
*/
|
|
37
|
+
export class HallRoomImpl {
|
|
38
|
+
roomId;
|
|
39
|
+
sessionId;
|
|
40
|
+
#listeners = {
|
|
41
|
+
transcript: new Set(),
|
|
42
|
+
conceptMention: new Set(),
|
|
43
|
+
relationProposed: new Set(),
|
|
44
|
+
speakerChanged: new Set(),
|
|
45
|
+
peerJoined: new Set(),
|
|
46
|
+
peerLeft: new Set(),
|
|
47
|
+
recordingManifest: new Set(),
|
|
48
|
+
closed: new Set(),
|
|
49
|
+
};
|
|
50
|
+
constructor(roomId, sessionId) {
|
|
51
|
+
this.roomId = roomId;
|
|
52
|
+
this.sessionId = sessionId;
|
|
53
|
+
}
|
|
54
|
+
on(event, listener) {
|
|
55
|
+
;
|
|
56
|
+
this.#listeners[event].add(listener);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
off(event, listener) {
|
|
60
|
+
;
|
|
61
|
+
this.#listeners[event].delete(listener);
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
/** @internal Dispatches an incoming server event to all registered listeners. */
|
|
65
|
+
_dispatch(event, payload) {
|
|
66
|
+
for (const listener of this.#listeners[event]) {
|
|
67
|
+
try {
|
|
68
|
+
listener(payload);
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
console.error(`[Hall] uncaught error in room '${this.roomId}' ${event} listener:`, e);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ─── HallClient ───────────────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Product-backend WebSocket client for the Hall real-time communication server.
|
|
79
|
+
*
|
|
80
|
+
* Create one instance per product process. Maintains a single authenticated control-plane
|
|
81
|
+
* WebSocket to `hall.soulcraft.com`. All room management and event routing goes through
|
|
82
|
+
* this single connection — do not create multiple instances per product.
|
|
83
|
+
*
|
|
84
|
+
* Auto-reconnects on unexpected disconnect (configurable via `reconnectDelayMs`).
|
|
85
|
+
* In-flight promises are rejected on disconnect; register `onReconnect` to re-create rooms.
|
|
86
|
+
*/
|
|
87
|
+
export class HallClient {
|
|
88
|
+
url;
|
|
89
|
+
#productName;
|
|
90
|
+
#secret;
|
|
91
|
+
#reconnectDelayMs;
|
|
92
|
+
#ws = null;
|
|
93
|
+
#authenticated = false;
|
|
94
|
+
#closed = false;
|
|
95
|
+
#rooms = new Map();
|
|
96
|
+
#pendingConnect = null;
|
|
97
|
+
#pendingCreateRoom = new Map();
|
|
98
|
+
#pendingCloseRoom = new Map();
|
|
99
|
+
#pendingSessionToken = new Map();
|
|
100
|
+
#pendingRoomList = [];
|
|
101
|
+
#disconnectListeners = new Set();
|
|
102
|
+
#reconnectListeners = new Set();
|
|
103
|
+
/**
|
|
104
|
+
* @param options - Connection options: url, productName, secret, and optional reconnectDelayMs.
|
|
105
|
+
*/
|
|
106
|
+
constructor(options) {
|
|
107
|
+
this.url = options.url;
|
|
108
|
+
this.#productName = options.productName;
|
|
109
|
+
this.#secret = options.secret;
|
|
110
|
+
this.#reconnectDelayMs = options.reconnectDelayMs ?? 2000;
|
|
111
|
+
}
|
|
112
|
+
// ── Connection lifecycle ───────────────────────────────────────────────────
|
|
113
|
+
/**
|
|
114
|
+
* Connect to the Hall server and authenticate with the product shared secret.
|
|
115
|
+
* Must be called once at startup before any other method.
|
|
116
|
+
*
|
|
117
|
+
* @returns Resolves when `authOk` is received from the server.
|
|
118
|
+
* @throws {Error} If auth fails or the WebSocket cannot connect.
|
|
119
|
+
*/
|
|
120
|
+
connect() {
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
this.#pendingConnect = { resolve, reject };
|
|
123
|
+
this.#openSocket();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Gracefully close all active rooms and disconnect from the Hall server.
|
|
128
|
+
* After calling this, the instance cannot be reconnected.
|
|
129
|
+
*/
|
|
130
|
+
async close() {
|
|
131
|
+
this.#closed = true;
|
|
132
|
+
for (const roomId of this.#rooms.keys()) {
|
|
133
|
+
await this.closeRoom(roomId).catch(() => undefined);
|
|
134
|
+
}
|
|
135
|
+
this.#ws?.close();
|
|
136
|
+
this.#ws = null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Register a listener for unexpected disconnects (not triggered by `close()`).
|
|
140
|
+
* Use this to log the event and prepare to re-create rooms after reconnect.
|
|
141
|
+
*
|
|
142
|
+
* @param listener - Called with a human-readable reason string (e.g. `"code 1006"`).
|
|
143
|
+
*/
|
|
144
|
+
onDisconnect(listener) {
|
|
145
|
+
this.#disconnectListeners.add(listener);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Register a listener for successful reconnections.
|
|
149
|
+
* On reconnect, rooms from before the disconnect are gone — re-create them here.
|
|
150
|
+
*
|
|
151
|
+
* @param listener - Called with no arguments when the reconnect auth succeeds.
|
|
152
|
+
*/
|
|
153
|
+
onReconnect(listener) {
|
|
154
|
+
this.#reconnectListeners.add(listener);
|
|
155
|
+
}
|
|
156
|
+
// ── Room management ────────────────────────────────────────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* Create a new room on the Hall server.
|
|
159
|
+
*
|
|
160
|
+
* @param roomId - Unique room identifier (e.g. Brainy session entity ID).
|
|
161
|
+
* @param options - Room configuration: peer limit, transcription, recording, concept list.
|
|
162
|
+
* @returns The HallRoom handle — register event listeners on it immediately.
|
|
163
|
+
* @throws {Error} If a room with the same ID already exists or the server returns an error.
|
|
164
|
+
*/
|
|
165
|
+
createRoom(roomId, options = {}) {
|
|
166
|
+
this.#requireConnected();
|
|
167
|
+
return new Promise((resolve, reject) => {
|
|
168
|
+
this.#pendingCreateRoom.set(roomId, { resolve, reject });
|
|
169
|
+
this.#send({ t: 'createRoom', d: { roomId, options } });
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Close a room and disconnect all its peers.
|
|
174
|
+
*
|
|
175
|
+
* @param roomId - The room ID passed to `createRoom`.
|
|
176
|
+
* @throws {Error} If the server returns an error.
|
|
177
|
+
*/
|
|
178
|
+
closeRoom(roomId) {
|
|
179
|
+
this.#requireConnected();
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
this.#pendingCloseRoom.set(roomId, { resolve, reject });
|
|
182
|
+
this.#send({ t: 'closeRoom', d: { roomId } });
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Return the IDs of all active rooms managed by this connection.
|
|
187
|
+
*
|
|
188
|
+
* @returns Array of room ID strings currently active on the server.
|
|
189
|
+
*/
|
|
190
|
+
listRooms() {
|
|
191
|
+
this.#requireConnected();
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
this.#pendingRoomList.push({ resolve, reject });
|
|
194
|
+
this.#send({ t: 'listRooms', d: {} });
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Return an active room handle by ID, or `undefined` if not found.
|
|
199
|
+
*
|
|
200
|
+
* @param roomId - The room ID passed to `createRoom`.
|
|
201
|
+
*/
|
|
202
|
+
getRoom(roomId) {
|
|
203
|
+
return this.#rooms.get(roomId);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Mint a short-lived HMAC session token for a browser peer.
|
|
207
|
+
* Pass `{ token, hallUrl }` to the browser — **never** the product secret.
|
|
208
|
+
*
|
|
209
|
+
* @param roomId - The room the browser peer will join.
|
|
210
|
+
* @param peerId - The peer's unique identifier (e.g. authenticated user ID).
|
|
211
|
+
* @param ttlSecs - Token lifetime in seconds (default: 300).
|
|
212
|
+
* @returns `{ token, expiresAt }` — send `token` and `this.url` to the browser.
|
|
213
|
+
*/
|
|
214
|
+
createSessionToken(roomId, peerId, ttlSecs) {
|
|
215
|
+
this.#requireConnected();
|
|
216
|
+
const key = `${roomId}:${peerId}`;
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
this.#pendingSessionToken.set(key, { resolve, reject });
|
|
219
|
+
this.#send({ t: 'createSessionToken', d: { roomId, peerId, ttlSecs } });
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Start per-track MKV recording for an active room.
|
|
224
|
+
* The room emits `recordingManifest` when `stopRecording` is called.
|
|
225
|
+
*
|
|
226
|
+
* @param roomId - The room to start recording.
|
|
227
|
+
*/
|
|
228
|
+
startRecording(roomId) {
|
|
229
|
+
this.#requireConnected();
|
|
230
|
+
return new Promise((resolve, _reject) => {
|
|
231
|
+
// Hall sends `recordingStarted` as an informational ack — errors arrive as
|
|
232
|
+
// t:'error' messages and are routed to #rejectFirstPending.
|
|
233
|
+
this.#send({ t: 'startRecording', d: { roomId } });
|
|
234
|
+
resolve();
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Stop recording for a room. Hall writes track files and emits `recordingManifest`
|
|
239
|
+
* on the room handle with absolute paths to the recorded MKV files.
|
|
240
|
+
*
|
|
241
|
+
* @param roomId - The room to stop recording.
|
|
242
|
+
*/
|
|
243
|
+
stopRecording(roomId) {
|
|
244
|
+
this.#requireConnected();
|
|
245
|
+
return new Promise((resolve, _reject) => {
|
|
246
|
+
this.#send({ t: 'stopRecording', d: { roomId } });
|
|
247
|
+
resolve();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
// ── Private: socket management ─────────────────────────────────────────────
|
|
251
|
+
#openSocket() {
|
|
252
|
+
const ws = new WebSocket(`${this.url}/ws/product`);
|
|
253
|
+
ws.binaryType = 'arraybuffer';
|
|
254
|
+
this.#ws = ws;
|
|
255
|
+
ws.onopen = () => {
|
|
256
|
+
this.#send({ t: 'authProduct', d: { productName: this.#productName, secret: this.#secret } });
|
|
257
|
+
};
|
|
258
|
+
ws.onmessage = (ev) => {
|
|
259
|
+
let msg;
|
|
260
|
+
try {
|
|
261
|
+
msg = decodeHallMessage(ev.data);
|
|
262
|
+
}
|
|
263
|
+
catch (e) {
|
|
264
|
+
console.error('[Hall] failed to decode server message:', e);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.#handleMessage(msg);
|
|
268
|
+
};
|
|
269
|
+
ws.onclose = (ev) => {
|
|
270
|
+
this.#authenticated = false;
|
|
271
|
+
const reason = ev.reason || `code ${ev.code}`;
|
|
272
|
+
if (this.#pendingConnect) {
|
|
273
|
+
this.#pendingConnect.reject(new Error(`Hall connection closed: ${reason}`));
|
|
274
|
+
this.#pendingConnect = null;
|
|
275
|
+
}
|
|
276
|
+
this.#rejectAllPending(new Error(`Hall disconnected: ${reason}`));
|
|
277
|
+
if (!this.#closed && this.#reconnectDelayMs > 0) {
|
|
278
|
+
for (const l of this.#disconnectListeners)
|
|
279
|
+
l(reason);
|
|
280
|
+
setTimeout(() => this.#reconnect(), this.#reconnectDelayMs);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
ws.onerror = () => {
|
|
284
|
+
console.error('[Hall] WebSocket error');
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
#reconnect() {
|
|
288
|
+
if (this.#closed)
|
|
289
|
+
return;
|
|
290
|
+
this.#rooms.clear();
|
|
291
|
+
this.#openSocket();
|
|
292
|
+
this.connect()
|
|
293
|
+
.then(() => {
|
|
294
|
+
for (const l of this.#reconnectListeners)
|
|
295
|
+
l();
|
|
296
|
+
})
|
|
297
|
+
.catch((e) => {
|
|
298
|
+
console.error('[Hall] reconnect auth failed:', e);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
#send(msg) {
|
|
302
|
+
if (!this.#ws || this.#ws.readyState !== WebSocket.OPEN) {
|
|
303
|
+
throw new Error('Hall: not connected — call hall.connect() first');
|
|
304
|
+
}
|
|
305
|
+
this.#ws.send(encodeHallMessage(msg));
|
|
306
|
+
}
|
|
307
|
+
#requireConnected() {
|
|
308
|
+
if (!this.#authenticated) {
|
|
309
|
+
throw new Error('Hall: not authenticated — await hall.connect() first');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// ── Private: message routing ───────────────────────────────────────────────
|
|
313
|
+
#handleMessage(msg) {
|
|
314
|
+
switch (msg.t) {
|
|
315
|
+
case 'authOk':
|
|
316
|
+
this.#authenticated = true;
|
|
317
|
+
this.#pendingConnect?.resolve();
|
|
318
|
+
this.#pendingConnect = null;
|
|
319
|
+
break;
|
|
320
|
+
case 'authFailed':
|
|
321
|
+
this.#pendingConnect?.reject(new Error(msg.d.reason));
|
|
322
|
+
this.#pendingConnect = null;
|
|
323
|
+
this.#ws?.close();
|
|
324
|
+
break;
|
|
325
|
+
case 'roomCreated': {
|
|
326
|
+
const room = new HallRoomImpl(msg.d.roomId, msg.d.sessionId);
|
|
327
|
+
this.#rooms.set(msg.d.roomId, room);
|
|
328
|
+
const pending = this.#pendingCreateRoom.get(msg.d.roomId);
|
|
329
|
+
if (pending) {
|
|
330
|
+
this.#pendingCreateRoom.delete(msg.d.roomId);
|
|
331
|
+
pending.resolve(room);
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
case 'roomClosed': {
|
|
336
|
+
const room = this.#rooms.get(msg.d.roomId);
|
|
337
|
+
if (room) {
|
|
338
|
+
room._dispatch('closed', { roomId: msg.d.roomId });
|
|
339
|
+
this.#rooms.delete(msg.d.roomId);
|
|
340
|
+
}
|
|
341
|
+
const pending = this.#pendingCloseRoom.get(msg.d.roomId);
|
|
342
|
+
if (pending) {
|
|
343
|
+
this.#pendingCloseRoom.delete(msg.d.roomId);
|
|
344
|
+
pending.resolve();
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
case 'roomList': {
|
|
349
|
+
const pending = this.#pendingRoomList.shift();
|
|
350
|
+
pending?.resolve(msg.d.roomIds);
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
case 'sessionToken': {
|
|
354
|
+
// Resolve the first pending token request — the server responds in order.
|
|
355
|
+
for (const [key, pending] of this.#pendingSessionToken) {
|
|
356
|
+
this.#pendingSessionToken.delete(key);
|
|
357
|
+
pending.resolve({ token: msg.d.token, expiresAt: msg.d.expiresAt });
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
case 'error':
|
|
363
|
+
console.warn(`[Hall] server error ${msg.d.code}: ${msg.d.message}`);
|
|
364
|
+
this.#rejectFirstPending(new Error(msg.d.message));
|
|
365
|
+
break;
|
|
366
|
+
case 'transcript':
|
|
367
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'transcript', msg.d);
|
|
368
|
+
break;
|
|
369
|
+
case 'conceptMention':
|
|
370
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'conceptMention', msg.d);
|
|
371
|
+
break;
|
|
372
|
+
case 'relationProposed':
|
|
373
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'relationProposed', msg.d);
|
|
374
|
+
break;
|
|
375
|
+
case 'speakerChanged':
|
|
376
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'speakerChanged', msg.d);
|
|
377
|
+
break;
|
|
378
|
+
case 'peerJoined':
|
|
379
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'peerJoined', msg.d);
|
|
380
|
+
break;
|
|
381
|
+
case 'peerLeft':
|
|
382
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'peerLeft', msg.d);
|
|
383
|
+
break;
|
|
384
|
+
case 'recordingManifest':
|
|
385
|
+
this.#dispatchRoomEvent(msg.d.roomId, 'recordingManifest', msg.d.manifest);
|
|
386
|
+
break;
|
|
387
|
+
case 'recordingStarted':
|
|
388
|
+
case 'dataSent':
|
|
389
|
+
// Informational acks — no pending promise to resolve.
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
#dispatchRoomEvent(roomId, event, payload) {
|
|
394
|
+
const room = this.#rooms.get(roomId);
|
|
395
|
+
if (room) {
|
|
396
|
+
room._dispatch(event, payload);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
console.warn(`[Hall] received '${event}' for unknown room '${roomId}'`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
#rejectAllPending(err) {
|
|
403
|
+
this.#pendingCreateRoom.forEach((p) => p.reject(err));
|
|
404
|
+
this.#pendingCreateRoom.clear();
|
|
405
|
+
this.#pendingCloseRoom.forEach((p) => p.reject(err));
|
|
406
|
+
this.#pendingCloseRoom.clear();
|
|
407
|
+
this.#pendingSessionToken.forEach((p) => p.reject(err));
|
|
408
|
+
this.#pendingSessionToken.clear();
|
|
409
|
+
this.#pendingRoomList.forEach((p) => p.reject(err));
|
|
410
|
+
this.#pendingRoomList.length = 0;
|
|
411
|
+
}
|
|
412
|
+
#rejectFirstPending(err) {
|
|
413
|
+
for (const [key, p] of this.#pendingCreateRoom) {
|
|
414
|
+
this.#pendingCreateRoom.delete(key);
|
|
415
|
+
p.reject(err);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
for (const [key, p] of this.#pendingCloseRoom) {
|
|
419
|
+
this.#pendingCloseRoom.delete(key);
|
|
420
|
+
p.reject(err);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
for (const [key, p] of this.#pendingSessionToken) {
|
|
424
|
+
this.#pendingSessionToken.delete(key);
|
|
425
|
+
p.reject(err);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
this.#pendingRoomList.shift()?.reject(err);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// ─── Factory ──────────────────────────────────────────────────────────────────
|
|
432
|
+
/**
|
|
433
|
+
* Create a server-mode Hall module that connects to the Hall standalone server.
|
|
434
|
+
*
|
|
435
|
+
* Returns a `HallModule` backed by a `HallClient`. Call `connect()` once at startup.
|
|
436
|
+
* In typical server mode SDK usage, `createSDK` calls this automatically when
|
|
437
|
+
* `hall` options are provided in `ServerSDKOptions`.
|
|
438
|
+
*
|
|
439
|
+
* @param options - Connection options: url, productName, secret, reconnectDelayMs.
|
|
440
|
+
* @returns A `HallModule` instance (not yet connected — call `module.connect()`).
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* import { createHallModule } from '@soulcraft/sdk/server'
|
|
445
|
+
*
|
|
446
|
+
* const hall = createHallModule({
|
|
447
|
+
* url: process.env.HALL_URL!,
|
|
448
|
+
* productName: 'academy',
|
|
449
|
+
* secret: process.env.HALL_ACADEMY_SECRET!,
|
|
450
|
+
* })
|
|
451
|
+
* await hall.connect()
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
export function createHallModule(options) {
|
|
455
|
+
return new HallClient(options);
|
|
456
|
+
}
|
|
457
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/modules/hall/server.ts"],"names":[],"mappings":"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"}
|