vg-x07df 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1055 -613
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +762 -215
- package/dist/index.d.ts +762 -215
- package/dist/index.mjs +1035 -614
- package/dist/index.mjs.map +1 -1
- package/dist/livekit/index.cjs +61 -0
- package/dist/livekit/index.cjs.map +1 -1
- package/dist/livekit/index.d.cts +6 -1
- package/dist/livekit/index.d.ts +6 -1
- package/dist/livekit/index.mjs +66 -0
- package/dist/livekit/index.mjs.map +1 -1
- package/package.json +7 -2
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,10 @@ import React, { createContext, useMemo, useEffect, useContext, useState, useRef
|
|
|
2
2
|
import { io } from 'socket.io-client';
|
|
3
3
|
import { create } from 'zustand';
|
|
4
4
|
import { immer } from 'zustand/middleware/immer';
|
|
5
|
+
import mitt from 'mitt';
|
|
5
6
|
import { z } from 'zod';
|
|
7
|
+
import { Room } from 'livekit-client';
|
|
8
|
+
import { useParticipants, useParticipantInfo } from '@livekit/components-react';
|
|
6
9
|
|
|
7
10
|
// src/provider/RtcProvider.tsx
|
|
8
11
|
|
|
@@ -128,10 +131,10 @@ function setGlobalLoggerOptions(options) {
|
|
|
128
131
|
|
|
129
132
|
// src/state/types.ts
|
|
130
133
|
var defaultState = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
},
|
|
134
|
+
initiated: false,
|
|
135
|
+
session: null,
|
|
136
|
+
incomingInvite: null,
|
|
137
|
+
outgoingInvites: {},
|
|
135
138
|
errors: []
|
|
136
139
|
};
|
|
137
140
|
|
|
@@ -154,14 +157,14 @@ var useRtcStore = create()(
|
|
|
154
157
|
var rtcStore = useRtcStore;
|
|
155
158
|
|
|
156
159
|
// src/state/errors.ts
|
|
157
|
-
function pushError(code, message, context,
|
|
160
|
+
function pushError(code, message, context, logger4) {
|
|
158
161
|
const error = {
|
|
159
162
|
code,
|
|
160
163
|
message,
|
|
161
164
|
timestamp: Date.now(),
|
|
162
165
|
context
|
|
163
166
|
};
|
|
164
|
-
|
|
167
|
+
logger4?.("error", message, { code, context });
|
|
165
168
|
rtcStore.getState().addError(error);
|
|
166
169
|
}
|
|
167
170
|
function clearErrors(predicate) {
|
|
@@ -173,73 +176,73 @@ function clearErrors(predicate) {
|
|
|
173
176
|
}
|
|
174
177
|
});
|
|
175
178
|
}
|
|
176
|
-
function pushSocketValidationError(eventType, issues, payload,
|
|
179
|
+
function pushSocketValidationError(eventType, issues, payload, logger4) {
|
|
177
180
|
pushError(
|
|
178
181
|
"SOCKET_PAYLOAD",
|
|
179
182
|
`Invalid ${eventType} event payload`,
|
|
180
183
|
{ eventType, issues, payload },
|
|
181
|
-
|
|
184
|
+
logger4
|
|
182
185
|
);
|
|
183
186
|
}
|
|
184
|
-
function pushIdentityGuardError(reason, expected, received,
|
|
187
|
+
function pushIdentityGuardError(reason, expected, received, logger4) {
|
|
185
188
|
pushError(
|
|
186
189
|
"JOIN_FLOW",
|
|
187
190
|
// Use new error code
|
|
188
191
|
`Identity guard failed: ${reason}`,
|
|
189
192
|
{ expected, received },
|
|
190
|
-
|
|
193
|
+
logger4
|
|
191
194
|
);
|
|
192
195
|
}
|
|
193
|
-
function pushLiveKitConnectError(message, error,
|
|
196
|
+
function pushLiveKitConnectError(message, error, logger4) {
|
|
194
197
|
pushError(
|
|
195
198
|
"LIVEKIT_CONNECT",
|
|
196
199
|
`LiveKit connection failed: ${message}`,
|
|
197
200
|
{ originalError: error },
|
|
198
|
-
|
|
201
|
+
logger4
|
|
199
202
|
);
|
|
200
203
|
}
|
|
201
|
-
function pushStaleEventError(eventType, reason, context,
|
|
204
|
+
function pushStaleEventError(eventType, reason, context, logger4) {
|
|
202
205
|
pushError(
|
|
203
206
|
"JOIN_FLOW",
|
|
204
207
|
// Use new error code
|
|
205
208
|
`Ignored stale ${eventType} event: ${reason}`,
|
|
206
209
|
context,
|
|
207
|
-
|
|
210
|
+
logger4
|
|
208
211
|
);
|
|
209
212
|
}
|
|
210
|
-
function pushApiError(operation, error,
|
|
213
|
+
function pushApiError(operation, error, logger4) {
|
|
211
214
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
212
215
|
pushError(
|
|
213
216
|
"API_ERROR",
|
|
214
217
|
`API ${operation} failed: ${errorMessage}`,
|
|
215
218
|
{ operation, originalError: error },
|
|
216
|
-
|
|
219
|
+
logger4
|
|
217
220
|
);
|
|
218
221
|
}
|
|
219
|
-
function pushNetworkError(operation, error,
|
|
222
|
+
function pushNetworkError(operation, error, logger4) {
|
|
220
223
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
221
224
|
pushError(
|
|
222
225
|
"NETWORK",
|
|
223
226
|
`Network error during ${operation}: ${errorMessage}`,
|
|
224
227
|
{ operation, originalError: error },
|
|
225
|
-
|
|
228
|
+
logger4
|
|
226
229
|
);
|
|
227
230
|
}
|
|
228
|
-
function pushMediaPermissionError(device, error,
|
|
231
|
+
function pushMediaPermissionError(device, error, logger4) {
|
|
229
232
|
pushError(
|
|
230
233
|
"MEDIA_PERMISSION",
|
|
231
234
|
`${device} permission denied`,
|
|
232
235
|
{ device, originalError: error },
|
|
233
|
-
|
|
236
|
+
logger4
|
|
234
237
|
);
|
|
235
238
|
}
|
|
236
|
-
function pushDeviceError(operation, device, error,
|
|
239
|
+
function pushDeviceError(operation, device, error, logger4) {
|
|
237
240
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
238
241
|
pushError(
|
|
239
242
|
"DEVICE_SWITCH",
|
|
240
243
|
`Failed to ${operation} ${device}: ${errorMessage}`,
|
|
241
244
|
{ operation, device, originalError: error },
|
|
242
|
-
|
|
245
|
+
logger4
|
|
243
246
|
);
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -300,248 +303,37 @@ var BaseSocketHandler = class {
|
|
|
300
303
|
return this.options.livekit;
|
|
301
304
|
}
|
|
302
305
|
};
|
|
303
|
-
|
|
304
|
-
// src/utils/participant-adapter.ts
|
|
305
|
-
function findCaller(participants) {
|
|
306
|
-
return participants.find((p) => p.role === "CALLER" || p.role === "HOST") || null;
|
|
307
|
-
}
|
|
308
|
-
function extractCallerInfo(participants) {
|
|
309
|
-
const caller = findCaller(participants);
|
|
310
|
-
if (!caller) return null;
|
|
311
|
-
const result = {
|
|
312
|
-
id: caller.id,
|
|
313
|
-
name: [caller.firstName, caller.lastName].filter(Boolean).join(" ") || `Guest ${caller.id}`
|
|
314
|
-
};
|
|
315
|
-
if (caller.profilePhoto) {
|
|
316
|
-
result.avatarUrl = caller.profilePhoto;
|
|
317
|
-
}
|
|
318
|
-
return result;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// src/core/events/event-bus.ts
|
|
322
|
-
var logger = createLogger("core:event-bus");
|
|
323
306
|
var EventBus = class {
|
|
324
|
-
constructor(
|
|
325
|
-
this.
|
|
326
|
-
this.isDebugMode = false;
|
|
327
|
-
this.eventHistory = [];
|
|
328
|
-
this.maxHistorySize = 100;
|
|
329
|
-
this.isDebugMode = debugMode;
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Subscribe to events of a specific type
|
|
333
|
-
*/
|
|
334
|
-
on(eventType, handler, filter) {
|
|
335
|
-
const actualHandler = filter ? (event) => {
|
|
336
|
-
if (filter(event)) {
|
|
337
|
-
handler(event);
|
|
338
|
-
}
|
|
339
|
-
} : handler;
|
|
340
|
-
if (!this.listeners.has(eventType)) {
|
|
341
|
-
this.listeners.set(eventType, /* @__PURE__ */ new Set());
|
|
342
|
-
}
|
|
343
|
-
this.listeners.get(eventType)?.add(actualHandler);
|
|
344
|
-
if (this.isDebugMode) {
|
|
345
|
-
logger.debug(`Event listener added for: ${eventType}`, {
|
|
346
|
-
eventType,
|
|
347
|
-
totalListeners: this.listeners.get(eventType)?.size
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
return {
|
|
351
|
-
unsubscribe: () => {
|
|
352
|
-
const handlers = this.listeners.get(eventType);
|
|
353
|
-
if (handlers) {
|
|
354
|
-
handlers.delete(actualHandler);
|
|
355
|
-
if (handlers.size === 0) {
|
|
356
|
-
this.listeners.delete(eventType);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
if (this.isDebugMode) {
|
|
360
|
-
logger.debug(`Event listener removed for: ${eventType}`, {
|
|
361
|
-
eventType,
|
|
362
|
-
remainingListeners: handlers?.size || 0
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
};
|
|
307
|
+
constructor() {
|
|
308
|
+
this.emitter = mitt();
|
|
367
309
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
onPattern(pattern, handler, filter) {
|
|
372
|
-
const regex = new RegExp(pattern.replace(/\*/g, ".*"));
|
|
373
|
-
const patternHandler = (event) => {
|
|
374
|
-
if (regex.test(event.type)) {
|
|
375
|
-
if (filter && !filter(event)) return;
|
|
376
|
-
handler(event);
|
|
377
|
-
}
|
|
310
|
+
on(eventType, handler) {
|
|
311
|
+
const wrappedHandler = (event) => {
|
|
312
|
+
handler(event);
|
|
378
313
|
};
|
|
379
|
-
|
|
380
|
-
if (!this.listeners.has(patternKey)) {
|
|
381
|
-
this.listeners.set(patternKey, /* @__PURE__ */ new Set());
|
|
382
|
-
}
|
|
383
|
-
this.listeners.get(patternKey)?.add(patternHandler);
|
|
384
|
-
if (this.isDebugMode) {
|
|
385
|
-
logger.debug(`Pattern listener added: ${pattern}`, { pattern });
|
|
386
|
-
}
|
|
314
|
+
this.emitter.on(eventType.toString(), wrappedHandler);
|
|
387
315
|
return {
|
|
388
316
|
unsubscribe: () => {
|
|
389
|
-
|
|
390
|
-
if (handlers) {
|
|
391
|
-
handlers.delete(patternHandler);
|
|
392
|
-
if (handlers.size === 0) {
|
|
393
|
-
this.listeners.delete(patternKey);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (this.isDebugMode) {
|
|
397
|
-
logger.debug(`Pattern listener removed: ${pattern}`, { pattern });
|
|
398
|
-
}
|
|
317
|
+
this.emitter.off(eventType.toString(), wrappedHandler);
|
|
399
318
|
}
|
|
400
319
|
};
|
|
401
320
|
}
|
|
402
|
-
|
|
403
|
-
* Subscribe to a single event occurrence
|
|
404
|
-
*/
|
|
405
|
-
once(eventType, handler, filter) {
|
|
406
|
-
const subscription = this.on(
|
|
407
|
-
eventType,
|
|
408
|
-
(event) => {
|
|
409
|
-
handler(event);
|
|
410
|
-
subscription.unsubscribe();
|
|
411
|
-
},
|
|
412
|
-
filter
|
|
413
|
-
);
|
|
414
|
-
return subscription;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Emit an event
|
|
418
|
-
*/
|
|
419
|
-
emit(eventType, payload, source = "user") {
|
|
321
|
+
emit(eventType, payload) {
|
|
420
322
|
const event = {
|
|
421
323
|
type: eventType.toString(),
|
|
422
324
|
payload,
|
|
423
|
-
timestamp: Date.now()
|
|
424
|
-
source
|
|
325
|
+
timestamp: Date.now()
|
|
425
326
|
};
|
|
426
|
-
this.
|
|
427
|
-
if (this.isDebugMode) {
|
|
428
|
-
logger.debug(`Event emitted: ${eventType}`, {
|
|
429
|
-
eventType,
|
|
430
|
-
payload,
|
|
431
|
-
source,
|
|
432
|
-
timestamp: event.timestamp
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
const exactListeners = this.listeners.get(eventType.toString());
|
|
436
|
-
if (exactListeners) {
|
|
437
|
-
for (const handler of exactListeners) {
|
|
438
|
-
try {
|
|
439
|
-
handler(event);
|
|
440
|
-
} catch (error) {
|
|
441
|
-
logger.error(`Error in event handler for ${eventType}`, {
|
|
442
|
-
error,
|
|
443
|
-
eventType,
|
|
444
|
-
payload
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
this.listeners.forEach((handlers, key) => {
|
|
450
|
-
if (key.startsWith("__pattern__")) {
|
|
451
|
-
for (const handler of handlers) {
|
|
452
|
-
try {
|
|
453
|
-
handler(event);
|
|
454
|
-
} catch (error) {
|
|
455
|
-
logger.error(`Error in pattern handler for ${eventType}`, {
|
|
456
|
-
error,
|
|
457
|
-
eventType,
|
|
458
|
-
pattern: key,
|
|
459
|
-
payload
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
});
|
|
327
|
+
this.emitter.emit(eventType.toString(), event);
|
|
465
328
|
}
|
|
466
|
-
/**
|
|
467
|
-
* Remove all listeners for a specific event type
|
|
468
|
-
*/
|
|
469
329
|
off(eventType) {
|
|
470
|
-
this.
|
|
471
|
-
if (this.isDebugMode) {
|
|
472
|
-
logger.debug(`All listeners removed for: ${eventType}`, { eventType });
|
|
473
|
-
}
|
|
330
|
+
this.emitter.off(eventType.toString());
|
|
474
331
|
}
|
|
475
|
-
/**
|
|
476
|
-
* Remove all listeners
|
|
477
|
-
*/
|
|
478
332
|
removeAllListeners() {
|
|
479
|
-
|
|
480
|
-
(sum, handlers) => sum + handlers.size,
|
|
481
|
-
0
|
|
482
|
-
);
|
|
483
|
-
this.listeners.clear();
|
|
484
|
-
if (this.isDebugMode) {
|
|
485
|
-
logger.debug("All listeners removed", { removedCount: totalListeners });
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* Get the count of listeners for an event type
|
|
490
|
-
*/
|
|
491
|
-
listenerCount(eventType) {
|
|
492
|
-
return this.listeners.get(eventType.toString())?.size || 0;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Get all event types that have listeners
|
|
496
|
-
*/
|
|
497
|
-
getEventTypes() {
|
|
498
|
-
return Array.from(this.listeners.keys());
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Enable or disable debug mode
|
|
502
|
-
*/
|
|
503
|
-
setDebugMode(enabled) {
|
|
504
|
-
this.isDebugMode = enabled;
|
|
505
|
-
logger.debug(`Debug mode ${enabled ? "enabled" : "disabled"}`);
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Get event history for debugging
|
|
509
|
-
*/
|
|
510
|
-
getEventHistory() {
|
|
511
|
-
return [...this.eventHistory];
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Clear event history
|
|
515
|
-
*/
|
|
516
|
-
clearHistory() {
|
|
517
|
-
this.eventHistory = [];
|
|
518
|
-
if (this.isDebugMode) {
|
|
519
|
-
logger.debug("Event history cleared");
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* Get events matching a filter
|
|
524
|
-
*/
|
|
525
|
-
getEventsWhere(filter) {
|
|
526
|
-
return this.eventHistory.filter(filter);
|
|
527
|
-
}
|
|
528
|
-
addToHistory(event) {
|
|
529
|
-
this.eventHistory.push(event);
|
|
530
|
-
if (this.eventHistory.length > this.maxHistorySize) {
|
|
531
|
-
this.eventHistory.shift();
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Set maximum history size
|
|
536
|
-
*/
|
|
537
|
-
setMaxHistorySize(size) {
|
|
538
|
-
this.maxHistorySize = size;
|
|
539
|
-
if (this.eventHistory.length > size) {
|
|
540
|
-
this.eventHistory = this.eventHistory.slice(-size);
|
|
541
|
-
}
|
|
333
|
+
this.emitter.all.clear();
|
|
542
334
|
}
|
|
543
335
|
};
|
|
544
|
-
var eventBus = new EventBus(
|
|
336
|
+
var eventBus = new EventBus();
|
|
545
337
|
|
|
546
338
|
// src/core/events/types.ts
|
|
547
339
|
var SdkEventType = /* @__PURE__ */ ((SdkEventType2) => {
|
|
@@ -566,163 +358,482 @@ var SdkEventType = /* @__PURE__ */ ((SdkEventType2) => {
|
|
|
566
358
|
SdkEventType2["ERROR_OCCURRED"] = "error:occurred";
|
|
567
359
|
return SdkEventType2;
|
|
568
360
|
})(SdkEventType || {});
|
|
569
|
-
var
|
|
570
|
-
id: z.string(),
|
|
571
|
-
firstName: z.string().nullable(),
|
|
572
|
-
lastName: z.string().nullable(),
|
|
573
|
-
username: z.string().nullable(),
|
|
574
|
-
profilePhoto: z.string().nullable(),
|
|
575
|
-
role: z.enum(["CALLER", "CALLEE", "HOST", "MEMBER"]).optional()
|
|
576
|
-
});
|
|
577
|
-
var callIncomingSchema = z.object({
|
|
361
|
+
var callCancelledSchema = z.object({
|
|
578
362
|
callId: z.string(),
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
});
|
|
584
|
-
var callParticipantAcceptedSchema = z.object({
|
|
585
|
-
callId: z.string(),
|
|
586
|
-
participantId: z.string(),
|
|
587
|
-
participant: socketParticipantSchema,
|
|
588
|
-
acceptedAt: z.string().optional()
|
|
589
|
-
});
|
|
590
|
-
var callJoinInfoSchema = z.object({
|
|
363
|
+
status: z.literal("cancelled"),
|
|
364
|
+
cancelledAt: z.string()
|
|
365
|
+
}).strict();
|
|
366
|
+
var callCreatedSchema = z.object({
|
|
591
367
|
callId: z.string(),
|
|
592
|
-
|
|
593
|
-
url: z.string().optional(),
|
|
368
|
+
status: z.literal("pending"),
|
|
594
369
|
roomName: z.string(),
|
|
595
|
-
|
|
596
|
-
|
|
370
|
+
createdAt: z.string(),
|
|
371
|
+
host: z.object({
|
|
372
|
+
firstName: z.string().nullable(),
|
|
373
|
+
lastName: z.string().nullable(),
|
|
374
|
+
username: z.string().nullable(),
|
|
375
|
+
email: z.string().nullable(),
|
|
376
|
+
profilePhoto: z.string().nullable(),
|
|
377
|
+
userId: z.string()
|
|
378
|
+
}).strict(),
|
|
379
|
+
participants: z.array(z.object({
|
|
380
|
+
firstName: z.string().nullable(),
|
|
381
|
+
lastName: z.string().nullable(),
|
|
382
|
+
username: z.string().nullable(),
|
|
383
|
+
email: z.string().nullable(),
|
|
384
|
+
profilePhoto: z.string().nullable(),
|
|
385
|
+
userId: z.string()
|
|
386
|
+
}).strict())
|
|
387
|
+
}).strict();
|
|
597
388
|
var callEndedSchema = z.object({
|
|
598
389
|
callId: z.string(),
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
390
|
+
endedAt: z.string(),
|
|
391
|
+
endedByUserId: z.string().optional(),
|
|
392
|
+
reason: z.string().optional()
|
|
393
|
+
}).strict();
|
|
394
|
+
var callInviteSchema = z.object({
|
|
603
395
|
callId: z.string(),
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
396
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
397
|
+
caller: z.object({
|
|
398
|
+
firstName: z.string().nullable(),
|
|
399
|
+
lastName: z.string().nullable(),
|
|
400
|
+
username: z.string().nullable(),
|
|
401
|
+
email: z.string().nullable(),
|
|
402
|
+
profilePhoto: z.string().nullable(),
|
|
403
|
+
userId: z.string()
|
|
404
|
+
}).strict(),
|
|
405
|
+
mode: z.enum(["VIDEO", "AUDIO"]),
|
|
406
|
+
expiresAt: z.string(),
|
|
407
|
+
expiresInMs: z.number()
|
|
408
|
+
}).strict();
|
|
409
|
+
var callInviteAcceptedSchema = z.object({
|
|
410
|
+
callId: z.string(),
|
|
411
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
412
|
+
participant: z.object({
|
|
413
|
+
firstName: z.string().nullable(),
|
|
414
|
+
lastName: z.string().nullable(),
|
|
415
|
+
username: z.string().nullable(),
|
|
416
|
+
email: z.string().nullable(),
|
|
417
|
+
profilePhoto: z.string().nullable(),
|
|
418
|
+
userId: z.string()
|
|
419
|
+
}).strict(),
|
|
420
|
+
acceptedAt: z.string()
|
|
421
|
+
}).strict();
|
|
422
|
+
var callInviteCancelledSchema = z.object({
|
|
608
423
|
callId: z.string(),
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
424
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
425
|
+
cancelledByUserId: z.string(),
|
|
426
|
+
cancelledAt: z.string(),
|
|
427
|
+
reason: z.string()
|
|
428
|
+
}).strict();
|
|
429
|
+
var callInviteDeclinedSchema = z.object({
|
|
614
430
|
callId: z.string(),
|
|
431
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
432
|
+
participant: z.object({
|
|
433
|
+
firstName: z.string().nullable(),
|
|
434
|
+
lastName: z.string().nullable(),
|
|
435
|
+
username: z.string().nullable(),
|
|
436
|
+
email: z.string().nullable(),
|
|
437
|
+
profilePhoto: z.string().nullable(),
|
|
438
|
+
userId: z.string()
|
|
439
|
+
}).strict(),
|
|
615
440
|
reason: z.string().optional(),
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
441
|
+
declinedAt: z.string()
|
|
442
|
+
}).strict();
|
|
443
|
+
var callInviteMissedSchema = z.object({
|
|
444
|
+
callId: z.string(),
|
|
445
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
446
|
+
participant: z.object({
|
|
447
|
+
firstName: z.string().nullable(),
|
|
448
|
+
lastName: z.string().nullable(),
|
|
449
|
+
username: z.string().nullable(),
|
|
450
|
+
email: z.string().nullable(),
|
|
451
|
+
profilePhoto: z.string().nullable(),
|
|
452
|
+
userId: z.string()
|
|
453
|
+
}).strict(),
|
|
454
|
+
missedAt: z.string()
|
|
455
|
+
}).strict();
|
|
456
|
+
var callInviteSentSchema = z.object({
|
|
457
|
+
callId: z.string(),
|
|
458
|
+
invitee: z.object({
|
|
459
|
+
firstName: z.string().nullable(),
|
|
460
|
+
lastName: z.string().nullable(),
|
|
461
|
+
username: z.string().nullable(),
|
|
462
|
+
email: z.string().nullable(),
|
|
463
|
+
profilePhoto: z.string().nullable(),
|
|
464
|
+
userId: z.string()
|
|
465
|
+
}).strict(),
|
|
466
|
+
status: z.literal("sent")
|
|
467
|
+
}).strict();
|
|
468
|
+
var callJoinInfoSchema = z.object({
|
|
469
|
+
callId: z.string(),
|
|
470
|
+
token: z.string(),
|
|
471
|
+
roomName: z.string(),
|
|
472
|
+
lkUrl: z.string(),
|
|
473
|
+
role: z.enum(["HOST", "PARTICIPANT", "GUEST"]),
|
|
474
|
+
participantId: z.string().optional()
|
|
475
|
+
}).strict();
|
|
476
|
+
var callMissedSchema = z.object({
|
|
477
|
+
callId: z.string(),
|
|
478
|
+
endedAt: z.string()
|
|
479
|
+
}).strict();
|
|
480
|
+
var callParticipantAddedSchema = z.object({
|
|
481
|
+
callId: z.string(),
|
|
482
|
+
status: z.enum(["pending", "active", "ended"]),
|
|
483
|
+
participant: z.object({
|
|
484
|
+
participantId: z.string(),
|
|
485
|
+
userId: z.string(),
|
|
486
|
+
firstName: z.string().optional(),
|
|
487
|
+
lastName: z.string().optional(),
|
|
488
|
+
username: z.string().optional(),
|
|
489
|
+
email: z.string().optional(),
|
|
490
|
+
profilePhoto: z.string().optional(),
|
|
491
|
+
role: z.enum(["HOST", "PARTICIPANT", "GUEST"]),
|
|
492
|
+
joinState: z.enum(["not_joined", "joined"])
|
|
493
|
+
}).strict()
|
|
494
|
+
}).strict();
|
|
619
495
|
|
|
620
|
-
// src/core/socketio/handlers/
|
|
621
|
-
var
|
|
496
|
+
// src/core/socketio/handlers/invite.handler.ts
|
|
497
|
+
var InviteHandler = class extends BaseSocketHandler {
|
|
622
498
|
constructor() {
|
|
623
499
|
super(...arguments);
|
|
624
|
-
this.eventName = "call
|
|
625
|
-
this.schema =
|
|
500
|
+
this.eventName = "call:invite";
|
|
501
|
+
this.schema = callInviteSchema;
|
|
626
502
|
}
|
|
627
503
|
handle(data) {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
504
|
+
this.logger.info("Incoming call invitation", {
|
|
505
|
+
callId: data.callId,
|
|
506
|
+
caller: data.caller.userId,
|
|
507
|
+
mode: data.mode
|
|
508
|
+
});
|
|
633
509
|
this.updateStore((state) => {
|
|
510
|
+
state.incomingInvite = {
|
|
511
|
+
callId: data.callId,
|
|
512
|
+
caller: {
|
|
513
|
+
userId: data.caller.userId,
|
|
514
|
+
firstName: data.caller.firstName,
|
|
515
|
+
lastName: data.caller.lastName,
|
|
516
|
+
username: data.caller.username,
|
|
517
|
+
email: data.caller.email,
|
|
518
|
+
profilePhoto: data.caller.profilePhoto
|
|
519
|
+
},
|
|
520
|
+
mode: data.mode,
|
|
521
|
+
expiresAt: data.expiresAt,
|
|
522
|
+
expiresInMs: data.expiresInMs
|
|
523
|
+
};
|
|
634
524
|
state.session = {
|
|
635
525
|
id: data.callId,
|
|
636
|
-
status: "
|
|
637
|
-
mode: data.
|
|
638
|
-
|
|
526
|
+
status: "pending",
|
|
527
|
+
mode: data.mode,
|
|
528
|
+
role: "PARTICIPANT"
|
|
639
529
|
};
|
|
640
|
-
state.room.participants = {};
|
|
641
530
|
});
|
|
642
|
-
eventBus.emit(
|
|
643
|
-
|
|
644
|
-
{
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
participants: data.participants
|
|
531
|
+
eventBus.emit("call:incoming" /* CALL_INCOMING */, {
|
|
532
|
+
callId: data.callId,
|
|
533
|
+
caller: {
|
|
534
|
+
id: data.caller.userId,
|
|
535
|
+
firstName: data.caller.firstName,
|
|
536
|
+
lastName: data.caller.lastName,
|
|
537
|
+
avatarUrl: data.caller.profilePhoto
|
|
650
538
|
},
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
539
|
+
type: data.mode,
|
|
540
|
+
timestamp: Date.now()
|
|
541
|
+
});
|
|
542
|
+
this.logger.debug("Incoming invite state updated");
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// src/core/socketio/handlers/invite-sent.handler.ts
|
|
547
|
+
var InviteSentHandler = class extends BaseSocketHandler {
|
|
548
|
+
constructor() {
|
|
549
|
+
super(...arguments);
|
|
550
|
+
this.eventName = "call:inviteSent";
|
|
551
|
+
this.schema = callInviteSentSchema;
|
|
552
|
+
}
|
|
553
|
+
handle(data) {
|
|
554
|
+
const currentState = rtcStore.getState();
|
|
555
|
+
this.logger.info("Invitation sent to participant", {
|
|
556
|
+
callId: data.callId,
|
|
557
|
+
invitee: data.invitee.userId
|
|
558
|
+
});
|
|
559
|
+
if (currentState.session?.id !== data.callId) {
|
|
560
|
+
pushStaleEventError("call:inviteSent", "callId mismatch", {
|
|
561
|
+
eventCallId: data.callId,
|
|
562
|
+
sessionCallId: currentState.session?.id
|
|
563
|
+
});
|
|
564
|
+
this.logger.warn("Ignoring invite sent for different call", { callId: data.callId });
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
this.updateStore((state) => {
|
|
568
|
+
const userId = data.invitee.userId;
|
|
569
|
+
state.outgoingInvites[userId] = {
|
|
570
|
+
userId,
|
|
571
|
+
status: "sent",
|
|
572
|
+
participant: {
|
|
573
|
+
userId: data.invitee.userId,
|
|
574
|
+
firstName: data.invitee.firstName,
|
|
575
|
+
lastName: data.invitee.lastName,
|
|
576
|
+
username: data.invitee.username,
|
|
577
|
+
email: data.invitee.email,
|
|
578
|
+
profilePhoto: data.invitee.profilePhoto
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
});
|
|
582
|
+
eventBus.emit("participant:invited" /* PARTICIPANT_INVITED */, {
|
|
583
|
+
callId: data.callId,
|
|
584
|
+
participant: {
|
|
585
|
+
id: data.invitee.userId,
|
|
586
|
+
firstName: data.invitee.firstName,
|
|
587
|
+
lastName: data.invitee.lastName,
|
|
588
|
+
avatarUrl: data.invitee.profilePhoto
|
|
589
|
+
},
|
|
590
|
+
timestamp: Date.now()
|
|
591
|
+
});
|
|
592
|
+
this.logger.debug("Outgoing invite tracked", {
|
|
593
|
+
userId: data.invitee.userId
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
// src/core/socketio/handlers/invite-accepted.handler.ts
|
|
599
|
+
var InviteAcceptedHandler = class extends BaseSocketHandler {
|
|
600
|
+
constructor() {
|
|
601
|
+
super(...arguments);
|
|
602
|
+
this.eventName = "call:inviteAccepted";
|
|
603
|
+
this.schema = callInviteAcceptedSchema;
|
|
604
|
+
}
|
|
605
|
+
handle(data) {
|
|
606
|
+
const currentState = rtcStore.getState();
|
|
607
|
+
this.logger.info("Participant accepted invitation", {
|
|
654
608
|
callId: data.callId,
|
|
655
|
-
|
|
656
|
-
|
|
609
|
+
participant: data.participant.userId
|
|
610
|
+
});
|
|
611
|
+
if (currentState.session?.id !== data.callId) {
|
|
612
|
+
pushStaleEventError("call:inviteAccepted", "callId mismatch", {
|
|
613
|
+
eventCallId: data.callId,
|
|
614
|
+
sessionCallId: currentState.session?.id
|
|
615
|
+
});
|
|
616
|
+
this.logger.warn("Ignoring accept event for different call", { callId: data.callId });
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
this.updateStore((state) => {
|
|
620
|
+
const userId = data.participant.userId;
|
|
621
|
+
if (state.outgoingInvites[userId]) {
|
|
622
|
+
state.outgoingInvites[userId].status = "accepted";
|
|
623
|
+
} else {
|
|
624
|
+
state.outgoingInvites[userId] = {
|
|
625
|
+
userId,
|
|
626
|
+
status: "accepted",
|
|
627
|
+
participant: {
|
|
628
|
+
userId: data.participant.userId,
|
|
629
|
+
firstName: data.participant.firstName,
|
|
630
|
+
lastName: data.participant.lastName,
|
|
631
|
+
username: data.participant.username,
|
|
632
|
+
email: data.participant.email,
|
|
633
|
+
profilePhoto: data.participant.profilePhoto
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
this.logger.debug("Outgoing invite marked as accepted", {
|
|
639
|
+
userId: data.participant.userId
|
|
657
640
|
});
|
|
658
641
|
}
|
|
659
642
|
};
|
|
660
643
|
|
|
661
|
-
// src/core/socketio/handlers/
|
|
662
|
-
var
|
|
644
|
+
// src/core/socketio/handlers/invite-declined.handler.ts
|
|
645
|
+
var InviteDeclinedHandler = class extends BaseSocketHandler {
|
|
663
646
|
constructor() {
|
|
664
647
|
super(...arguments);
|
|
665
|
-
this.eventName = "call
|
|
666
|
-
this.schema =
|
|
648
|
+
this.eventName = "call:inviteDeclined";
|
|
649
|
+
this.schema = callInviteDeclinedSchema;
|
|
667
650
|
}
|
|
668
|
-
|
|
651
|
+
handle(data) {
|
|
669
652
|
const currentState = rtcStore.getState();
|
|
670
|
-
|
|
671
|
-
|
|
653
|
+
this.logger.info("Participant declined invitation", {
|
|
654
|
+
callId: data.callId,
|
|
655
|
+
participant: data.participant.userId,
|
|
656
|
+
reason: data.reason
|
|
657
|
+
});
|
|
658
|
+
if (currentState.session?.id !== data.callId) {
|
|
659
|
+
pushStaleEventError("call:inviteDeclined", "callId mismatch", {
|
|
672
660
|
eventCallId: data.callId,
|
|
673
|
-
sessionCallId: currentState.session
|
|
661
|
+
sessionCallId: currentState.session?.id
|
|
674
662
|
});
|
|
663
|
+
this.logger.warn("Ignoring decline event for different call", { callId: data.callId });
|
|
675
664
|
return;
|
|
676
665
|
}
|
|
677
666
|
this.updateStore((state) => {
|
|
678
|
-
|
|
667
|
+
const userId = data.participant.userId;
|
|
668
|
+
if (state.outgoingInvites[userId]) {
|
|
669
|
+
state.outgoingInvites[userId].status = "declined";
|
|
670
|
+
} else {
|
|
671
|
+
state.outgoingInvites[userId] = {
|
|
672
|
+
userId,
|
|
673
|
+
status: "declined",
|
|
674
|
+
participant: {
|
|
675
|
+
userId: data.participant.userId,
|
|
676
|
+
firstName: data.participant.firstName,
|
|
677
|
+
lastName: data.participant.lastName,
|
|
678
|
+
username: data.participant.username,
|
|
679
|
+
email: data.participant.email,
|
|
680
|
+
profilePhoto: data.participant.profilePhoto
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
eventBus.emit("call:declined" /* CALL_DECLINED */, {
|
|
686
|
+
callId: data.callId,
|
|
687
|
+
participantId: data.participant.userId,
|
|
688
|
+
reason: data.reason,
|
|
689
|
+
timestamp: Date.now()
|
|
690
|
+
});
|
|
691
|
+
this.logger.debug("Outgoing invite marked as declined", {
|
|
692
|
+
userId: data.participant.userId
|
|
679
693
|
});
|
|
680
694
|
}
|
|
681
695
|
};
|
|
682
696
|
|
|
683
|
-
// src/core/socketio/handlers/
|
|
684
|
-
var
|
|
697
|
+
// src/core/socketio/handlers/invite-missed.handler.ts
|
|
698
|
+
var InviteMissedHandler = class extends BaseSocketHandler {
|
|
685
699
|
constructor() {
|
|
686
700
|
super(...arguments);
|
|
687
|
-
this.eventName = "call
|
|
688
|
-
this.schema =
|
|
701
|
+
this.eventName = "call:inviteMissed";
|
|
702
|
+
this.schema = callInviteMissedSchema;
|
|
689
703
|
}
|
|
690
704
|
handle(data) {
|
|
705
|
+
const currentState = rtcStore.getState();
|
|
706
|
+
this.logger.info("Participant missed invitation", {
|
|
707
|
+
callId: data.callId,
|
|
708
|
+
participant: data.participant.userId
|
|
709
|
+
});
|
|
710
|
+
if (currentState.session?.id !== data.callId) {
|
|
711
|
+
pushStaleEventError("call:inviteMissed", "callId mismatch", {
|
|
712
|
+
eventCallId: data.callId,
|
|
713
|
+
sessionCallId: currentState.session?.id
|
|
714
|
+
});
|
|
715
|
+
this.logger.warn("Ignoring missed invite for different call", { callId: data.callId });
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
691
718
|
this.updateStore((state) => {
|
|
692
|
-
|
|
693
|
-
|
|
719
|
+
const userId = data.participant.userId;
|
|
720
|
+
if (state.outgoingInvites[userId]) {
|
|
721
|
+
state.outgoingInvites[userId].status = "missed";
|
|
722
|
+
} else {
|
|
723
|
+
state.outgoingInvites[userId] = {
|
|
724
|
+
userId,
|
|
725
|
+
status: "missed",
|
|
726
|
+
participant: {
|
|
727
|
+
userId: data.participant.userId,
|
|
728
|
+
firstName: data.participant.firstName,
|
|
729
|
+
lastName: data.participant.lastName,
|
|
730
|
+
username: data.participant.username,
|
|
731
|
+
email: data.participant.email,
|
|
732
|
+
profilePhoto: data.participant.profilePhoto
|
|
733
|
+
}
|
|
734
|
+
};
|
|
694
735
|
}
|
|
695
736
|
});
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
);
|
|
737
|
+
this.logger.debug("Outgoing invite marked as missed", {
|
|
738
|
+
userId: data.participant.userId
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
// src/core/socketio/handlers/invite-cancelled.handler.ts
|
|
744
|
+
var InviteCancelledHandler = class extends BaseSocketHandler {
|
|
745
|
+
constructor() {
|
|
746
|
+
super(...arguments);
|
|
747
|
+
this.eventName = "call:inviteCancelled";
|
|
748
|
+
this.schema = callInviteCancelledSchema;
|
|
749
|
+
}
|
|
750
|
+
handle(data) {
|
|
751
|
+
const currentState = rtcStore.getState();
|
|
752
|
+
this.logger.info("Invitation cancelled by host", {
|
|
753
|
+
callId: data.callId,
|
|
754
|
+
cancelledBy: data.cancelledByUserId,
|
|
755
|
+
reason: data.reason
|
|
756
|
+
});
|
|
757
|
+
if (currentState.incomingInvite?.callId !== data.callId) {
|
|
758
|
+
this.logger.debug("Ignoring cancelled invite for different call", {
|
|
759
|
+
callId: data.callId
|
|
760
|
+
});
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
this.updateStore((state) => {
|
|
764
|
+
state.incomingInvite = null;
|
|
765
|
+
state.session = null;
|
|
766
|
+
});
|
|
767
|
+
eventBus.emit("call:canceled" /* CALL_CANCELED */, {
|
|
768
|
+
callId: data.callId,
|
|
769
|
+
reason: data.reason,
|
|
770
|
+
timestamp: Date.now()
|
|
771
|
+
});
|
|
772
|
+
this.logger.debug("Incoming invite cleared due to cancellation");
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
// src/core/socketio/handlers/call-created.handler.ts
|
|
777
|
+
var SessionCreatedHandler = class extends BaseSocketHandler {
|
|
778
|
+
constructor() {
|
|
779
|
+
super(...arguments);
|
|
780
|
+
this.eventName = "call:created";
|
|
781
|
+
this.schema = callCreatedSchema;
|
|
782
|
+
}
|
|
783
|
+
handle(data) {
|
|
784
|
+
this.logger.info("Call session created", {
|
|
785
|
+
callId: data.callId,
|
|
786
|
+
roomName: data.roomName,
|
|
787
|
+
host: data.host.userId,
|
|
788
|
+
participantCount: data.participants.length
|
|
789
|
+
});
|
|
790
|
+
this.updateStore((state) => {
|
|
791
|
+
state.initiated = true;
|
|
792
|
+
state.session = {
|
|
793
|
+
id: data.callId,
|
|
794
|
+
status: "pending",
|
|
795
|
+
mode: "VIDEO",
|
|
796
|
+
role: "HOST"
|
|
797
|
+
};
|
|
798
|
+
state.outgoingInvites = {};
|
|
799
|
+
});
|
|
800
|
+
eventBus.emit("call:initiated" /* CALL_INITIATED */, {
|
|
801
|
+
callId: data.callId,
|
|
802
|
+
participants: data.participants.map((p) => p.userId),
|
|
803
|
+
type: "VIDEO",
|
|
804
|
+
// Default, TODO: get from API request context
|
|
805
|
+
timestamp: Date.now()
|
|
806
|
+
});
|
|
807
|
+
this.logger.debug("Session created for outbound call");
|
|
706
808
|
}
|
|
707
809
|
};
|
|
708
810
|
|
|
709
811
|
// src/core/socketio/handlers/call-ended.handler.ts
|
|
710
|
-
var
|
|
812
|
+
var SessionEndedHandler = class extends BaseSocketHandler {
|
|
711
813
|
constructor() {
|
|
712
814
|
super(...arguments);
|
|
713
|
-
this.eventName = "call
|
|
815
|
+
this.eventName = "call:ended";
|
|
714
816
|
this.schema = callEndedSchema;
|
|
715
817
|
}
|
|
716
818
|
handle(data) {
|
|
819
|
+
const currentState = rtcStore.getState();
|
|
820
|
+
this.logger.info("Call session ended", {
|
|
821
|
+
callId: data.callId,
|
|
822
|
+
endedBy: data.endedByUserId,
|
|
823
|
+
reason: data.reason
|
|
824
|
+
});
|
|
825
|
+
if (currentState.session?.id !== data.callId) {
|
|
826
|
+
pushStaleEventError("call:ended", "callId mismatch", {
|
|
827
|
+
eventCallId: data.callId,
|
|
828
|
+
sessionCallId: currentState.session?.id
|
|
829
|
+
});
|
|
830
|
+
this.logger.warn("Ignoring end event for different call", { callId: data.callId });
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
717
833
|
this.updateStore((state) => {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
sessionCallId: state.session.id
|
|
722
|
-
});
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
state.session.status = "ENDED";
|
|
834
|
+
state.initiated = false;
|
|
835
|
+
state.session = null;
|
|
836
|
+
state.outgoingInvites = {};
|
|
726
837
|
state.room.participants = {};
|
|
727
838
|
});
|
|
728
839
|
if (this.livekit) {
|
|
@@ -730,83 +841,165 @@ var CallEndedHandler = class extends BaseSocketHandler {
|
|
|
730
841
|
this.logger.error("Error disconnecting from LiveKit", { error });
|
|
731
842
|
});
|
|
732
843
|
}
|
|
844
|
+
eventBus.emit("call:ended" /* CALL_ENDED */, {
|
|
845
|
+
callId: data.callId,
|
|
846
|
+
endedBy: data.endedByUserId,
|
|
847
|
+
reason: "user",
|
|
848
|
+
timestamp: Date.now()
|
|
849
|
+
});
|
|
850
|
+
this.logger.debug("Session cleared and LiveKit disconnected");
|
|
733
851
|
}
|
|
734
852
|
};
|
|
735
853
|
|
|
736
|
-
// src/core/socketio/handlers/call-
|
|
737
|
-
var
|
|
854
|
+
// src/core/socketio/handlers/call-cancelled.handler.ts
|
|
855
|
+
var SessionCancelledHandler = class extends BaseSocketHandler {
|
|
738
856
|
constructor() {
|
|
739
857
|
super(...arguments);
|
|
740
|
-
this.eventName = "call
|
|
741
|
-
this.schema =
|
|
858
|
+
this.eventName = "call:cancelled";
|
|
859
|
+
this.schema = callCancelledSchema;
|
|
742
860
|
}
|
|
743
|
-
|
|
861
|
+
handle(data) {
|
|
862
|
+
const currentState = rtcStore.getState();
|
|
863
|
+
this.logger.info("Call session cancelled", {
|
|
864
|
+
callId: data.callId,
|
|
865
|
+
status: data.status
|
|
866
|
+
});
|
|
867
|
+
if (currentState.session?.id !== data.callId) {
|
|
868
|
+
pushStaleEventError("call:cancelled", "callId mismatch", {
|
|
869
|
+
eventCallId: data.callId,
|
|
870
|
+
sessionCallId: currentState.session?.id
|
|
871
|
+
});
|
|
872
|
+
this.logger.warn("Ignoring cancel event for different call", { callId: data.callId });
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
744
875
|
this.updateStore((state) => {
|
|
745
|
-
state.
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
callId: data.callId
|
|
750
|
-
};
|
|
751
|
-
state.session.status = "READY_TO_JOIN";
|
|
876
|
+
state.initiated = false;
|
|
877
|
+
state.session = null;
|
|
878
|
+
state.outgoingInvites = {};
|
|
879
|
+
state.room.participants = {};
|
|
752
880
|
});
|
|
753
|
-
eventBus.emit(
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
roomName: data.roomName,
|
|
760
|
-
token: data.token
|
|
761
|
-
},
|
|
762
|
-
"socket"
|
|
763
|
-
);
|
|
881
|
+
eventBus.emit("call:canceled" /* CALL_CANCELED */, {
|
|
882
|
+
callId: data.callId,
|
|
883
|
+
reason: "cancelled by host",
|
|
884
|
+
timestamp: Date.now()
|
|
885
|
+
});
|
|
886
|
+
this.logger.debug("Session cleared due to cancellation");
|
|
764
887
|
}
|
|
765
888
|
};
|
|
766
889
|
|
|
767
|
-
// src/core/socketio/handlers/call-
|
|
768
|
-
var
|
|
890
|
+
// src/core/socketio/handlers/call-missed.handler.ts
|
|
891
|
+
var SessionMissedHandler = class extends BaseSocketHandler {
|
|
769
892
|
constructor() {
|
|
770
893
|
super(...arguments);
|
|
771
|
-
this.eventName = "call
|
|
772
|
-
this.schema =
|
|
894
|
+
this.eventName = "call:missed";
|
|
895
|
+
this.schema = callMissedSchema;
|
|
773
896
|
}
|
|
774
897
|
handle(data) {
|
|
775
|
-
const
|
|
776
|
-
this.logger.info(
|
|
898
|
+
const currentState = rtcStore.getState();
|
|
899
|
+
this.logger.info("Call missed by all participants", {
|
|
900
|
+
callId: data.callId
|
|
901
|
+
});
|
|
902
|
+
if (currentState.session?.id !== data.callId) {
|
|
903
|
+
pushStaleEventError("call:missed", "callId mismatch", {
|
|
904
|
+
eventCallId: data.callId,
|
|
905
|
+
sessionCallId: currentState.session?.id
|
|
906
|
+
});
|
|
907
|
+
this.logger.warn("Ignoring missed call for different session", { callId: data.callId });
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
777
910
|
this.updateStore((state) => {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
911
|
+
state.initiated = false;
|
|
912
|
+
state.session = null;
|
|
913
|
+
state.outgoingInvites = {};
|
|
914
|
+
state.room.participants = {};
|
|
915
|
+
});
|
|
916
|
+
eventBus.emit("call:timeout" /* CALL_TIMEOUT */, {
|
|
917
|
+
callId: data.callId,
|
|
918
|
+
reason: "All participants missed/declined",
|
|
919
|
+
timestamp: Date.now()
|
|
782
920
|
});
|
|
921
|
+
this.logger.debug("Session cleared - call was missed by all");
|
|
783
922
|
}
|
|
784
923
|
};
|
|
785
924
|
|
|
786
|
-
// src/core/socketio/handlers/
|
|
787
|
-
var
|
|
925
|
+
// src/core/socketio/handlers/join-info.handler.ts
|
|
926
|
+
var JoinInfoHandler = class extends BaseSocketHandler {
|
|
788
927
|
constructor() {
|
|
789
928
|
super(...arguments);
|
|
790
|
-
this.eventName = "call
|
|
791
|
-
this.schema =
|
|
929
|
+
this.eventName = "call:joinInfo";
|
|
930
|
+
this.schema = callJoinInfoSchema;
|
|
792
931
|
}
|
|
793
932
|
handle(data) {
|
|
794
|
-
const
|
|
795
|
-
this.logger.info(
|
|
933
|
+
const currentState = rtcStore.getState();
|
|
934
|
+
this.logger.info("Received LiveKit join info", {
|
|
796
935
|
callId: data.callId,
|
|
797
|
-
|
|
936
|
+
roomName: data.roomName,
|
|
937
|
+
role: data.role
|
|
798
938
|
});
|
|
939
|
+
if (currentState.session?.id !== data.callId) {
|
|
940
|
+
pushStaleEventError("call:joinInfo", "callId mismatch", {
|
|
941
|
+
eventCallId: data.callId,
|
|
942
|
+
sessionCallId: currentState.session?.id
|
|
943
|
+
});
|
|
944
|
+
this.logger.warn("Ignoring join info for unknown call", { callId: data.callId });
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
799
947
|
this.updateStore((state) => {
|
|
800
|
-
if (state.session
|
|
801
|
-
state.session.
|
|
802
|
-
|
|
948
|
+
if (state.session?.id === data.callId) {
|
|
949
|
+
state.session.livekitInfo = {
|
|
950
|
+
token: data.token,
|
|
951
|
+
roomName: data.roomName,
|
|
952
|
+
url: data.lkUrl
|
|
953
|
+
};
|
|
954
|
+
state.session.role = data.role;
|
|
803
955
|
}
|
|
804
956
|
});
|
|
957
|
+
eventBus.emit("join-info:received" /* JOIN_INFO_RECEIVED */, {
|
|
958
|
+
callId: data.callId,
|
|
959
|
+
participantId: data.participantId || "",
|
|
960
|
+
timestamp: Date.now(),
|
|
961
|
+
url: data.lkUrl,
|
|
962
|
+
token: data.token
|
|
963
|
+
});
|
|
964
|
+
this.logger.debug("Session updated with LiveKit credentials");
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
// src/core/socketio/handlers/participant-added.handler.ts
|
|
969
|
+
var ParticipantAddedHandler = class extends BaseSocketHandler {
|
|
970
|
+
constructor() {
|
|
971
|
+
super(...arguments);
|
|
972
|
+
this.eventName = "call:participantAdded";
|
|
973
|
+
this.schema = callParticipantAddedSchema;
|
|
974
|
+
}
|
|
975
|
+
handle(data) {
|
|
976
|
+
const currentState = rtcStore.getState();
|
|
977
|
+
this.logger.info("Participant added to call", {
|
|
978
|
+
callId: data.callId,
|
|
979
|
+
participantId: data.participant.participantId,
|
|
980
|
+
userId: data.participant.userId,
|
|
981
|
+
role: data.participant.role
|
|
982
|
+
});
|
|
983
|
+
if (currentState.session?.id !== data.callId) {
|
|
984
|
+
pushStaleEventError("call:participantAdded", "callId mismatch", {
|
|
985
|
+
eventCallId: data.callId,
|
|
986
|
+
sessionCallId: currentState.session?.id
|
|
987
|
+
});
|
|
988
|
+
this.logger.warn("Ignoring participant added for different call", { callId: data.callId });
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
eventBus.emit("participant:updated" /* PARTICIPANT_UPDATED */, {
|
|
992
|
+
participantId: data.participant.participantId,
|
|
993
|
+
timestamp: Date.now()
|
|
994
|
+
});
|
|
995
|
+
this.logger.debug("Participant added event processed", {
|
|
996
|
+
participantId: data.participant.participantId
|
|
997
|
+
});
|
|
805
998
|
}
|
|
806
999
|
};
|
|
807
1000
|
|
|
808
1001
|
// src/core/socketio/handlers/handler.registry.ts
|
|
809
|
-
var
|
|
1002
|
+
var logger = createLogger("socketio:registry");
|
|
810
1003
|
var SocketHandlerRegistry = class {
|
|
811
1004
|
constructor(options = {}) {
|
|
812
1005
|
this.options = options;
|
|
@@ -815,34 +1008,52 @@ var SocketHandlerRegistry = class {
|
|
|
815
1008
|
}
|
|
816
1009
|
initializeHandlers() {
|
|
817
1010
|
const handlers = [
|
|
818
|
-
|
|
819
|
-
new
|
|
820
|
-
new
|
|
821
|
-
new
|
|
822
|
-
new
|
|
823
|
-
|
|
824
|
-
new
|
|
1011
|
+
// Phase 1: Core flow handlers
|
|
1012
|
+
new InviteHandler(this.options),
|
|
1013
|
+
new JoinInfoHandler(this.options),
|
|
1014
|
+
new SessionEndedHandler(this.options),
|
|
1015
|
+
new SessionCreatedHandler(this.options),
|
|
1016
|
+
// Phase 2: Invite management handlers
|
|
1017
|
+
new InviteAcceptedHandler(this.options),
|
|
1018
|
+
new InviteDeclinedHandler(this.options),
|
|
1019
|
+
new InviteCancelledHandler(this.options),
|
|
1020
|
+
new InviteSentHandler(this.options),
|
|
1021
|
+
// Phase 3: Edge case handlers
|
|
1022
|
+
new InviteMissedHandler(this.options),
|
|
1023
|
+
new SessionCancelledHandler(this.options),
|
|
1024
|
+
new SessionMissedHandler(this.options),
|
|
1025
|
+
new ParticipantAddedHandler(this.options)
|
|
825
1026
|
];
|
|
826
1027
|
for (const handler of handlers) {
|
|
827
1028
|
this.handlers.set(handler.eventName, handler);
|
|
828
1029
|
}
|
|
1030
|
+
logger.info(`Registered ${handlers.length} socket event handlers`);
|
|
829
1031
|
}
|
|
830
1032
|
registerEventListeners(socket) {
|
|
831
1033
|
for (const [eventName, handler] of this.handlers) {
|
|
832
1034
|
socket.on(eventName, (rawData) => {
|
|
833
1035
|
handler.handleRaw(rawData).catch((error) => {
|
|
834
|
-
|
|
1036
|
+
logger.error(`Handler error for ${eventName}:`, error);
|
|
835
1037
|
});
|
|
836
1038
|
});
|
|
837
1039
|
}
|
|
1040
|
+
logger.debug("Event listeners registered on socket");
|
|
838
1041
|
}
|
|
839
1042
|
removeEventListeners(socket) {
|
|
840
1043
|
for (const eventName of this.handlers.keys()) {
|
|
841
1044
|
socket.off(eventName);
|
|
842
1045
|
}
|
|
1046
|
+
logger.debug("Event listeners removed from socket");
|
|
843
1047
|
}
|
|
844
1048
|
destroy() {
|
|
845
1049
|
this.handlers.clear();
|
|
1050
|
+
logger.debug("Handler registry destroyed");
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Get all registered event names
|
|
1054
|
+
*/
|
|
1055
|
+
getRegisteredEvents() {
|
|
1056
|
+
return Array.from(this.handlers.keys());
|
|
846
1057
|
}
|
|
847
1058
|
};
|
|
848
1059
|
|
|
@@ -1396,17 +1607,17 @@ var request = (config, options) => {
|
|
|
1396
1607
|
// src/generated/api/services.ts
|
|
1397
1608
|
var CallsService = class {
|
|
1398
1609
|
/**
|
|
1399
|
-
* @returns any
|
|
1610
|
+
* @returns any Invites sent successfully
|
|
1400
1611
|
* @throws ApiError
|
|
1401
1612
|
*/
|
|
1402
|
-
static
|
|
1613
|
+
static postSignalCallsInvite(data) {
|
|
1403
1614
|
const {
|
|
1404
1615
|
appId,
|
|
1405
1616
|
requestBody
|
|
1406
1617
|
} = data;
|
|
1407
1618
|
return request(OpenAPI, {
|
|
1408
1619
|
method: "POST",
|
|
1409
|
-
url: "/signal/calls",
|
|
1620
|
+
url: "/signal/calls/invite",
|
|
1410
1621
|
query: {
|
|
1411
1622
|
appId
|
|
1412
1623
|
},
|
|
@@ -1414,7 +1625,9 @@ var CallsService = class {
|
|
|
1414
1625
|
mediaType: "application/json",
|
|
1415
1626
|
errors: {
|
|
1416
1627
|
400: `Invalid request`,
|
|
1417
|
-
401: `Authentication required
|
|
1628
|
+
401: `Authentication required`,
|
|
1629
|
+
403: `User does not have permission to invite`,
|
|
1630
|
+
404: `Call not found`
|
|
1418
1631
|
}
|
|
1419
1632
|
});
|
|
1420
1633
|
}
|
|
@@ -1452,7 +1665,8 @@ var CallsService = class {
|
|
|
1452
1665
|
static postSignalCallsByCallIdDecline(data) {
|
|
1453
1666
|
const {
|
|
1454
1667
|
callId,
|
|
1455
|
-
appId
|
|
1668
|
+
appId,
|
|
1669
|
+
requestBody
|
|
1456
1670
|
} = data;
|
|
1457
1671
|
return request(OpenAPI, {
|
|
1458
1672
|
method: "POST",
|
|
@@ -1463,6 +1677,8 @@ var CallsService = class {
|
|
|
1463
1677
|
query: {
|
|
1464
1678
|
appId
|
|
1465
1679
|
},
|
|
1680
|
+
body: requestBody,
|
|
1681
|
+
mediaType: "application/json",
|
|
1466
1682
|
errors: {
|
|
1467
1683
|
400: `Invalid request`,
|
|
1468
1684
|
401: `Authentication required`,
|
|
@@ -1473,17 +1689,17 @@ var CallsService = class {
|
|
|
1473
1689
|
});
|
|
1474
1690
|
}
|
|
1475
1691
|
/**
|
|
1476
|
-
* @returns any
|
|
1692
|
+
* @returns any Call cancelled successfully
|
|
1477
1693
|
* @throws ApiError
|
|
1478
1694
|
*/
|
|
1479
|
-
static
|
|
1695
|
+
static postSignalCallsByCallIdCancel(data) {
|
|
1480
1696
|
const {
|
|
1481
1697
|
callId,
|
|
1482
1698
|
appId
|
|
1483
1699
|
} = data;
|
|
1484
1700
|
return request(OpenAPI, {
|
|
1485
1701
|
method: "POST",
|
|
1486
|
-
url: "/signal/calls/{callId}/
|
|
1702
|
+
url: "/signal/calls/{callId}/cancel",
|
|
1487
1703
|
path: {
|
|
1488
1704
|
callId
|
|
1489
1705
|
},
|
|
@@ -1493,151 +1709,180 @@ var CallsService = class {
|
|
|
1493
1709
|
errors: {
|
|
1494
1710
|
400: `Invalid request`,
|
|
1495
1711
|
401: `Authentication required`,
|
|
1496
|
-
403: `User
|
|
1712
|
+
403: `User does not have permission to cancel`,
|
|
1497
1713
|
404: `Call not found`,
|
|
1498
|
-
409: `Call cannot be
|
|
1714
|
+
409: `Call cannot be cancelled in current state`
|
|
1499
1715
|
}
|
|
1500
1716
|
});
|
|
1501
1717
|
}
|
|
1502
1718
|
/**
|
|
1503
|
-
* @returns any
|
|
1719
|
+
* @returns any Transfer initiated successfully
|
|
1504
1720
|
* @throws ApiError
|
|
1505
1721
|
*/
|
|
1506
|
-
static
|
|
1722
|
+
static postSignalCallsByCallIdTransfer(data) {
|
|
1507
1723
|
const {
|
|
1508
1724
|
callId,
|
|
1509
|
-
appId
|
|
1725
|
+
appId,
|
|
1726
|
+
requestBody
|
|
1510
1727
|
} = data;
|
|
1511
1728
|
return request(OpenAPI, {
|
|
1512
|
-
method: "
|
|
1513
|
-
url: "/signal/calls/{callId}",
|
|
1729
|
+
method: "POST",
|
|
1730
|
+
url: "/signal/calls/{callId}/transfer",
|
|
1514
1731
|
path: {
|
|
1515
1732
|
callId
|
|
1516
1733
|
},
|
|
1517
1734
|
query: {
|
|
1518
1735
|
appId
|
|
1519
1736
|
},
|
|
1737
|
+
body: requestBody,
|
|
1738
|
+
mediaType: "application/json",
|
|
1520
1739
|
errors: {
|
|
1521
1740
|
400: `Invalid request`,
|
|
1522
1741
|
401: `Authentication required`,
|
|
1523
|
-
403: `User does not have
|
|
1524
|
-
404: `Call not found
|
|
1742
|
+
403: `User does not have permission to transfer`,
|
|
1743
|
+
404: `Call not found`,
|
|
1744
|
+
409: `Call cannot be transferred in current state`
|
|
1525
1745
|
}
|
|
1526
1746
|
});
|
|
1527
1747
|
}
|
|
1528
1748
|
/**
|
|
1529
|
-
* @returns any Participant
|
|
1749
|
+
* @returns any Participant kicked successfully
|
|
1530
1750
|
* @throws ApiError
|
|
1531
1751
|
*/
|
|
1532
|
-
static
|
|
1752
|
+
static postSignalCallsByCallIdKick(data) {
|
|
1533
1753
|
const {
|
|
1534
|
-
|
|
1535
|
-
appId
|
|
1754
|
+
callId,
|
|
1755
|
+
appId,
|
|
1756
|
+
requestBody
|
|
1536
1757
|
} = data;
|
|
1537
1758
|
return request(OpenAPI, {
|
|
1538
|
-
method: "
|
|
1539
|
-
url: "/signal/calls/
|
|
1759
|
+
method: "POST",
|
|
1760
|
+
url: "/signal/calls/{callId}/kick",
|
|
1540
1761
|
path: {
|
|
1541
|
-
|
|
1762
|
+
callId
|
|
1542
1763
|
},
|
|
1543
1764
|
query: {
|
|
1544
1765
|
appId
|
|
1545
1766
|
},
|
|
1767
|
+
body: requestBody,
|
|
1768
|
+
mediaType: "application/json",
|
|
1546
1769
|
errors: {
|
|
1547
1770
|
400: `Invalid request`,
|
|
1548
1771
|
401: `Authentication required`,
|
|
1549
|
-
|
|
1772
|
+
403: `User does not have permission to kick`,
|
|
1773
|
+
404: `Call not found`,
|
|
1774
|
+
409: `Participant cannot be kicked in current state`
|
|
1550
1775
|
}
|
|
1551
1776
|
});
|
|
1552
1777
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
...response,
|
|
1583
|
-
callId,
|
|
1584
|
-
state: "ACTIVE",
|
|
1585
|
-
message: "Call accepted"
|
|
1586
|
-
};
|
|
1587
|
-
} catch (error) {
|
|
1588
|
-
this.handleApiError("accept", error);
|
|
1589
|
-
throw error;
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
async decline(callId) {
|
|
1593
|
-
try {
|
|
1594
|
-
const response = await CallsService.postSignalCallsByCallIdDecline({
|
|
1595
|
-
callId,
|
|
1596
|
-
appId: this.config.appId
|
|
1597
|
-
});
|
|
1598
|
-
return {
|
|
1599
|
-
...response,
|
|
1600
|
-
callId,
|
|
1601
|
-
state: "ENDED",
|
|
1602
|
-
message: "Call declined"
|
|
1603
|
-
};
|
|
1604
|
-
} catch (error) {
|
|
1605
|
-
this.handleApiError("decline", error);
|
|
1606
|
-
throw error;
|
|
1607
|
-
}
|
|
1778
|
+
/**
|
|
1779
|
+
* @returns any Participant muted successfully
|
|
1780
|
+
* @throws ApiError
|
|
1781
|
+
*/
|
|
1782
|
+
static postSignalCallsByCallIdMute(data) {
|
|
1783
|
+
const {
|
|
1784
|
+
callId,
|
|
1785
|
+
appId,
|
|
1786
|
+
requestBody
|
|
1787
|
+
} = data;
|
|
1788
|
+
return request(OpenAPI, {
|
|
1789
|
+
method: "POST",
|
|
1790
|
+
url: "/signal/calls/{callId}/mute",
|
|
1791
|
+
path: {
|
|
1792
|
+
callId
|
|
1793
|
+
},
|
|
1794
|
+
query: {
|
|
1795
|
+
appId
|
|
1796
|
+
},
|
|
1797
|
+
body: requestBody,
|
|
1798
|
+
mediaType: "application/json",
|
|
1799
|
+
errors: {
|
|
1800
|
+
400: `Invalid request`,
|
|
1801
|
+
401: `Authentication required`,
|
|
1802
|
+
403: `User does not have permission to mute`,
|
|
1803
|
+
404: `Call not found`,
|
|
1804
|
+
409: `Participant cannot be muted in current state`
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1608
1807
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1808
|
+
/**
|
|
1809
|
+
* @returns any Call ended successfully
|
|
1810
|
+
* @throws ApiError
|
|
1811
|
+
*/
|
|
1812
|
+
static postSignalCallsByCallIdEnd(data) {
|
|
1813
|
+
const {
|
|
1814
|
+
callId,
|
|
1815
|
+
appId
|
|
1816
|
+
} = data;
|
|
1817
|
+
return request(OpenAPI, {
|
|
1818
|
+
method: "POST",
|
|
1819
|
+
url: "/signal/calls/{callId}/end",
|
|
1820
|
+
path: {
|
|
1821
|
+
callId
|
|
1822
|
+
},
|
|
1823
|
+
query: {
|
|
1824
|
+
appId
|
|
1825
|
+
},
|
|
1826
|
+
errors: {
|
|
1827
|
+
400: `Invalid request`,
|
|
1828
|
+
401: `Authentication required`,
|
|
1829
|
+
403: `Only host can end call`,
|
|
1830
|
+
404: `Call not found`
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1625
1833
|
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1834
|
+
/**
|
|
1835
|
+
* @returns any Left call successfully
|
|
1836
|
+
* @throws ApiError
|
|
1837
|
+
*/
|
|
1838
|
+
static postSignalCallsByCallIdLeave(data) {
|
|
1839
|
+
const {
|
|
1840
|
+
callId,
|
|
1841
|
+
appId
|
|
1842
|
+
} = data;
|
|
1843
|
+
return request(OpenAPI, {
|
|
1844
|
+
method: "POST",
|
|
1845
|
+
url: "/signal/calls/{callId}/leave",
|
|
1846
|
+
path: {
|
|
1847
|
+
callId
|
|
1848
|
+
},
|
|
1849
|
+
query: {
|
|
1850
|
+
appId
|
|
1851
|
+
},
|
|
1852
|
+
errors: {
|
|
1853
|
+
400: `Invalid request`,
|
|
1854
|
+
401: `Authentication required`,
|
|
1855
|
+
404: `Call not found`
|
|
1856
|
+
}
|
|
1634
1857
|
});
|
|
1635
1858
|
}
|
|
1636
1859
|
};
|
|
1637
1860
|
|
|
1638
1861
|
// src/core/signal/api.config.ts
|
|
1862
|
+
var logger2 = createLogger("api-config");
|
|
1639
1863
|
var OpenApiConfigService = class _OpenApiConfigService {
|
|
1640
1864
|
constructor() {
|
|
1865
|
+
this.configured = false;
|
|
1866
|
+
OpenAPI.interceptors.request.use((request2) => {
|
|
1867
|
+
const headers = request2.headers;
|
|
1868
|
+
let authHeader = null;
|
|
1869
|
+
if (headers instanceof Headers) {
|
|
1870
|
+
authHeader = headers.get("Authorization") || null;
|
|
1871
|
+
} else if (headers && typeof headers === "object") {
|
|
1872
|
+
authHeader = headers["Authorization"] || null;
|
|
1873
|
+
}
|
|
1874
|
+
if (authHeader) {
|
|
1875
|
+
logger2.debug("API Request with Authorization header", {
|
|
1876
|
+
hasAuth: true,
|
|
1877
|
+
authPrefix: authHeader.substring(0, 20) + "..."
|
|
1878
|
+
});
|
|
1879
|
+
} else {
|
|
1880
|
+
logger2.warn("API Request WITHOUT Authorization header", {
|
|
1881
|
+
hasAuth: false
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
return request2;
|
|
1885
|
+
});
|
|
1641
1886
|
}
|
|
1642
1887
|
static getInstance() {
|
|
1643
1888
|
if (!_OpenApiConfigService.instance) {
|
|
@@ -1651,7 +1896,15 @@ var OpenApiConfigService = class _OpenApiConfigService {
|
|
|
1651
1896
|
const tokenFn = config.token;
|
|
1652
1897
|
OpenAPI.TOKEN = async (_options) => {
|
|
1653
1898
|
const result = tokenFn();
|
|
1654
|
-
|
|
1899
|
+
const token = typeof result === "string" ? result : await result;
|
|
1900
|
+
if (!token) {
|
|
1901
|
+
logger2.warn("Token provider returned empty token");
|
|
1902
|
+
} else {
|
|
1903
|
+
logger2.debug("Token resolved successfully", {
|
|
1904
|
+
tokenPrefix: token.substring(0, 10) + "..."
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
return token;
|
|
1655
1908
|
};
|
|
1656
1909
|
} else {
|
|
1657
1910
|
OpenAPI.TOKEN = config.token;
|
|
@@ -1661,6 +1914,14 @@ var OpenApiConfigService = class _OpenApiConfigService {
|
|
|
1661
1914
|
if (config.headers) {
|
|
1662
1915
|
OpenAPI.HEADERS = config.headers;
|
|
1663
1916
|
}
|
|
1917
|
+
this.configured = true;
|
|
1918
|
+
logger2.info("API configuration completed", {
|
|
1919
|
+
baseUrl: config.baseUrl,
|
|
1920
|
+
hasToken: !!config.token
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
isConfigured() {
|
|
1924
|
+
return this.configured;
|
|
1664
1925
|
}
|
|
1665
1926
|
setToken(token) {
|
|
1666
1927
|
OpenAPI.TOKEN = token;
|
|
@@ -1668,92 +1929,119 @@ var OpenApiConfigService = class _OpenApiConfigService {
|
|
|
1668
1929
|
};
|
|
1669
1930
|
var apiConfig = OpenApiConfigService.getInstance();
|
|
1670
1931
|
|
|
1671
|
-
// src/services/
|
|
1672
|
-
|
|
1673
|
-
|
|
1932
|
+
// src/services/calls.service.ts
|
|
1933
|
+
var logger3 = createLogger("calls-service");
|
|
1934
|
+
function createCallsService(config) {
|
|
1935
|
+
const { appId } = config;
|
|
1936
|
+
const ensureApiConfigured = () => {
|
|
1937
|
+
if (!apiConfig.isConfigured()) {
|
|
1938
|
+
logger3.error("API not configured before making call service request");
|
|
1939
|
+
throw new Error(
|
|
1940
|
+
"API configuration missing. Ensure the SDK is properly initialized."
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1674
1944
|
async function initiate(params) {
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
state.room.participants = {};
|
|
1687
|
-
logger3.debug("Call initiated - waiting for participants to join", {
|
|
1688
|
-
callId: response.id,
|
|
1689
|
-
invitedCount: response.participants?.length || 0
|
|
1690
|
-
});
|
|
1945
|
+
ensureApiConfigured();
|
|
1946
|
+
const requestBody = {
|
|
1947
|
+
mode: params.mode || "AUDIO",
|
|
1948
|
+
participants: params.invitees.map((userId) => ({ userId }))
|
|
1949
|
+
};
|
|
1950
|
+
if (params.callId) {
|
|
1951
|
+
requestBody.callId = params.callId;
|
|
1952
|
+
}
|
|
1953
|
+
return CallsService.postSignalCallsInvite({
|
|
1954
|
+
appId,
|
|
1955
|
+
requestBody
|
|
1691
1956
|
});
|
|
1692
|
-
return response;
|
|
1693
1957
|
}
|
|
1694
1958
|
async function accept(callId) {
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
id: callId,
|
|
1700
|
-
status: "ACCEPTED",
|
|
1701
|
-
// Call accepted but not yet joined media
|
|
1702
|
-
myRole: "CALLEE",
|
|
1703
|
-
initiatedByMe: false
|
|
1704
|
-
};
|
|
1705
|
-
state.room.participants = {};
|
|
1959
|
+
ensureApiConfigured();
|
|
1960
|
+
return CallsService.postSignalCallsByCallIdAccept({
|
|
1961
|
+
callId,
|
|
1962
|
+
appId
|
|
1706
1963
|
});
|
|
1707
|
-
return response;
|
|
1708
1964
|
}
|
|
1709
1965
|
async function decline(callId, reason) {
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
}
|
|
1718
|
-
});
|
|
1719
|
-
eventBus.emit(
|
|
1720
|
-
"call:declined" /* CALL_DECLINED */,
|
|
1721
|
-
{
|
|
1722
|
-
callId,
|
|
1723
|
-
reason,
|
|
1724
|
-
timestamp: Date.now()
|
|
1725
|
-
},
|
|
1726
|
-
"user"
|
|
1727
|
-
);
|
|
1728
|
-
return response;
|
|
1729
|
-
} catch (error) {
|
|
1730
|
-
logger3.error("Decline API failed", { callId, error });
|
|
1731
|
-
rtcStore.getState().patch((state) => {
|
|
1732
|
-
state.session.status = "IDLE";
|
|
1733
|
-
logger3.warn("Force-cleared session due to API failure");
|
|
1734
|
-
});
|
|
1735
|
-
eventBus.emit(
|
|
1736
|
-
"call:declined" /* CALL_DECLINED */,
|
|
1737
|
-
{
|
|
1738
|
-
callId,
|
|
1739
|
-
reason: "api_error",
|
|
1740
|
-
timestamp: Date.now()
|
|
1741
|
-
},
|
|
1742
|
-
"user"
|
|
1743
|
-
);
|
|
1744
|
-
throw error;
|
|
1966
|
+
ensureApiConfigured();
|
|
1967
|
+
const payload = {
|
|
1968
|
+
callId,
|
|
1969
|
+
appId
|
|
1970
|
+
};
|
|
1971
|
+
if (reason) {
|
|
1972
|
+
payload.requestBody = { reason };
|
|
1745
1973
|
}
|
|
1974
|
+
return CallsService.postSignalCallsByCallIdDecline(payload);
|
|
1975
|
+
}
|
|
1976
|
+
async function cancel(callId) {
|
|
1977
|
+
ensureApiConfigured();
|
|
1978
|
+
return CallsService.postSignalCallsByCallIdCancel({
|
|
1979
|
+
callId,
|
|
1980
|
+
appId
|
|
1981
|
+
});
|
|
1746
1982
|
}
|
|
1747
1983
|
async function leave(callId) {
|
|
1748
|
-
|
|
1749
|
-
|
|
1984
|
+
ensureApiConfigured();
|
|
1985
|
+
return CallsService.postSignalCallsByCallIdLeave({
|
|
1986
|
+
callId,
|
|
1987
|
+
appId
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
async function end(callId) {
|
|
1991
|
+
ensureApiConfigured();
|
|
1992
|
+
return CallsService.postSignalCallsByCallIdEnd({
|
|
1993
|
+
callId,
|
|
1994
|
+
appId
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
async function transfer(callId, targetParticipantId, reason) {
|
|
1998
|
+
ensureApiConfigured();
|
|
1999
|
+
const requestBody = {
|
|
2000
|
+
targetParticipantId
|
|
2001
|
+
};
|
|
2002
|
+
if (reason) {
|
|
2003
|
+
requestBody.reason = reason;
|
|
2004
|
+
}
|
|
2005
|
+
return CallsService.postSignalCallsByCallIdTransfer({
|
|
2006
|
+
callId,
|
|
2007
|
+
appId,
|
|
2008
|
+
requestBody
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
async function kick(callId, participantId, reason) {
|
|
2012
|
+
ensureApiConfigured();
|
|
2013
|
+
const requestBody = {
|
|
2014
|
+
participantId
|
|
2015
|
+
};
|
|
2016
|
+
if (reason) {
|
|
2017
|
+
requestBody.reason = reason;
|
|
2018
|
+
}
|
|
2019
|
+
return CallsService.postSignalCallsByCallIdKick({
|
|
2020
|
+
callId,
|
|
2021
|
+
appId,
|
|
2022
|
+
requestBody
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
async function mute(callId, participantId) {
|
|
2026
|
+
ensureApiConfigured();
|
|
2027
|
+
return CallsService.postSignalCallsByCallIdMute({
|
|
2028
|
+
callId,
|
|
2029
|
+
appId,
|
|
2030
|
+
requestBody: {
|
|
2031
|
+
participantId
|
|
2032
|
+
}
|
|
1750
2033
|
});
|
|
1751
2034
|
}
|
|
1752
2035
|
return {
|
|
1753
2036
|
initiate,
|
|
1754
2037
|
accept,
|
|
1755
2038
|
decline,
|
|
1756
|
-
|
|
2039
|
+
cancel,
|
|
2040
|
+
leave,
|
|
2041
|
+
end,
|
|
2042
|
+
transfer,
|
|
2043
|
+
kick,
|
|
2044
|
+
mute
|
|
1757
2045
|
};
|
|
1758
2046
|
}
|
|
1759
2047
|
|
|
@@ -1772,12 +2060,14 @@ function buildSdk(opts) {
|
|
|
1772
2060
|
setGlobalLoggerOptions(loggerOptions);
|
|
1773
2061
|
const auth = new AuthManager(opts.authProvider);
|
|
1774
2062
|
const socket = SocketManager.getInstance();
|
|
1775
|
-
const
|
|
2063
|
+
const callsService = createCallsService({ appId: opts.appId });
|
|
2064
|
+
apiConfig.configure({
|
|
1776
2065
|
baseUrl: opts.signalHost,
|
|
1777
|
-
|
|
1778
|
-
|
|
2066
|
+
token: async () => {
|
|
2067
|
+
const token = auth.getCurrentToken();
|
|
2068
|
+
return token || "";
|
|
2069
|
+
}
|
|
1779
2070
|
});
|
|
1780
|
-
const callActions = createCallActions(signal);
|
|
1781
2071
|
const cleanup = () => {
|
|
1782
2072
|
socket.destroy();
|
|
1783
2073
|
rtcStore.getState().reset();
|
|
@@ -1786,10 +2076,9 @@ function buildSdk(opts) {
|
|
|
1786
2076
|
store: rtcStore,
|
|
1787
2077
|
auth,
|
|
1788
2078
|
socket,
|
|
1789
|
-
|
|
1790
|
-
...callActions,
|
|
2079
|
+
calls: callsService,
|
|
1791
2080
|
cleanup,
|
|
1792
|
-
// API configuration
|
|
2081
|
+
// API configuration - can be called again to override if needed
|
|
1793
2082
|
configureApi: (config) => {
|
|
1794
2083
|
apiConfig.configure(config);
|
|
1795
2084
|
}
|
|
@@ -1804,24 +2093,6 @@ function RtcProvider({
|
|
|
1804
2093
|
}) {
|
|
1805
2094
|
const sdk = useMemo(() => buildSdk(options), [options]);
|
|
1806
2095
|
useEffect(() => {
|
|
1807
|
-
try {
|
|
1808
|
-
sdk.configureApi({
|
|
1809
|
-
baseUrl: options.signalHost,
|
|
1810
|
-
token: async () => {
|
|
1811
|
-
const token = sdk.auth.getCurrentToken();
|
|
1812
|
-
return token || "";
|
|
1813
|
-
}
|
|
1814
|
-
});
|
|
1815
|
-
options.log?.("info", "API configured successfully");
|
|
1816
|
-
} catch (error) {
|
|
1817
|
-
options.log?.("error", "Failed to configure API", error);
|
|
1818
|
-
rtcStore.getState().addError({
|
|
1819
|
-
code: "API_CONFIG_ERROR",
|
|
1820
|
-
message: "Failed to configure API",
|
|
1821
|
-
timestamp: Date.now(),
|
|
1822
|
-
context: error
|
|
1823
|
-
});
|
|
1824
|
-
}
|
|
1825
2096
|
sdk.socket.initialize(
|
|
1826
2097
|
options.signalHost,
|
|
1827
2098
|
sdk.auth,
|
|
@@ -1856,36 +2127,104 @@ var useSdk = () => {
|
|
|
1856
2127
|
// src/hooks/useCallState.ts
|
|
1857
2128
|
function useCallState() {
|
|
1858
2129
|
const session = useRtcStore((state) => state.session);
|
|
2130
|
+
if (!session) {
|
|
2131
|
+
return {
|
|
2132
|
+
id: null,
|
|
2133
|
+
status: null,
|
|
2134
|
+
mode: null,
|
|
2135
|
+
roomName: null
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
1859
2138
|
return {
|
|
1860
2139
|
id: session.id,
|
|
1861
2140
|
status: session.status,
|
|
1862
2141
|
mode: session.mode,
|
|
1863
|
-
roomName: session.livekitInfo?.roomName
|
|
2142
|
+
roomName: session.livekitInfo?.roomName || null
|
|
1864
2143
|
};
|
|
1865
2144
|
}
|
|
1866
2145
|
|
|
2146
|
+
// src/hooks/useSessionId.ts
|
|
2147
|
+
function useSessionId() {
|
|
2148
|
+
return useRtcStore((state) => state.session?.id ?? null);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
// src/hooks/useIncomingInvite.ts
|
|
2152
|
+
function useIncomingInvite() {
|
|
2153
|
+
return useRtcStore((state) => state.incomingInvite);
|
|
2154
|
+
}
|
|
2155
|
+
|
|
1867
2156
|
// src/hooks/useCallActions.ts
|
|
1868
2157
|
function useCallActions() {
|
|
1869
2158
|
const sdk = useSdk();
|
|
2159
|
+
const sessionId = useSessionId();
|
|
2160
|
+
const incomingInvite = useIncomingInvite();
|
|
1870
2161
|
return {
|
|
1871
2162
|
initiate: (participants, type) => {
|
|
1872
|
-
return sdk.initiate({ invitees: participants, mode: type });
|
|
2163
|
+
return sdk.calls.initiate({ invitees: participants, mode: type });
|
|
2164
|
+
},
|
|
2165
|
+
invite: (participants) => {
|
|
2166
|
+
if (!sessionId) {
|
|
2167
|
+
throw new Error("No active session to invite participants to");
|
|
2168
|
+
}
|
|
2169
|
+
const session = sdk.store.getState().session;
|
|
2170
|
+
const mode = session?.mode || "VIDEO";
|
|
2171
|
+
return sdk.calls.initiate({
|
|
2172
|
+
invitees: participants,
|
|
2173
|
+
mode,
|
|
2174
|
+
callId: sessionId
|
|
2175
|
+
});
|
|
2176
|
+
},
|
|
2177
|
+
accept: () => {
|
|
2178
|
+
if (!incomingInvite) {
|
|
2179
|
+
throw new Error("No incoming invite to accept");
|
|
2180
|
+
}
|
|
2181
|
+
return sdk.calls.accept(incomingInvite.callId);
|
|
2182
|
+
},
|
|
2183
|
+
decline: (reason) => {
|
|
2184
|
+
if (!incomingInvite) {
|
|
2185
|
+
throw new Error("No incoming invite to decline");
|
|
2186
|
+
}
|
|
2187
|
+
return sdk.calls.decline(incomingInvite.callId, reason);
|
|
2188
|
+
},
|
|
2189
|
+
cancel: () => {
|
|
2190
|
+
if (!sessionId) {
|
|
2191
|
+
throw new Error("No active session to cancel");
|
|
2192
|
+
}
|
|
2193
|
+
return sdk.calls.cancel(sessionId);
|
|
2194
|
+
},
|
|
2195
|
+
leave: () => {
|
|
2196
|
+
if (!sessionId) {
|
|
2197
|
+
throw new Error("No active session to leave");
|
|
2198
|
+
}
|
|
2199
|
+
return sdk.calls.leave(sessionId);
|
|
1873
2200
|
},
|
|
1874
|
-
|
|
1875
|
-
|
|
2201
|
+
end: () => {
|
|
2202
|
+
if (!sessionId) {
|
|
2203
|
+
throw new Error("No active session to end");
|
|
2204
|
+
}
|
|
2205
|
+
return sdk.calls.end(sessionId);
|
|
1876
2206
|
},
|
|
1877
|
-
|
|
1878
|
-
|
|
2207
|
+
transfer: (targetParticipantId, reason) => {
|
|
2208
|
+
if (!sessionId) {
|
|
2209
|
+
throw new Error("No active session to transfer");
|
|
2210
|
+
}
|
|
2211
|
+
return sdk.calls.transfer(sessionId, targetParticipantId, reason);
|
|
1879
2212
|
},
|
|
1880
|
-
|
|
1881
|
-
|
|
2213
|
+
kick: (participantId, reason) => {
|
|
2214
|
+
if (!sessionId) {
|
|
2215
|
+
throw new Error("No active session to kick participant from");
|
|
2216
|
+
}
|
|
2217
|
+
return sdk.calls.kick(sessionId, participantId, reason);
|
|
1882
2218
|
},
|
|
1883
|
-
|
|
1884
|
-
|
|
2219
|
+
mute: (participantId) => {
|
|
2220
|
+
if (!sessionId) {
|
|
2221
|
+
throw new Error("No active session to mute participant in");
|
|
2222
|
+
}
|
|
2223
|
+
return sdk.calls.mute(sessionId, participantId);
|
|
1885
2224
|
}
|
|
1886
2225
|
};
|
|
1887
2226
|
}
|
|
1888
|
-
function useEvent(eventType, callback
|
|
2227
|
+
function useEvent(eventType, callback) {
|
|
1889
2228
|
const [lastEvent, setLastEvent] = useState(
|
|
1890
2229
|
void 0
|
|
1891
2230
|
);
|
|
@@ -1898,14 +2237,96 @@ function useEvent(eventType, callback, filter) {
|
|
|
1898
2237
|
callbackRef.current(event);
|
|
1899
2238
|
}
|
|
1900
2239
|
};
|
|
1901
|
-
const subscription =
|
|
2240
|
+
const subscription = eventBus.on(eventType, handler);
|
|
1902
2241
|
return () => {
|
|
1903
2242
|
subscription.unsubscribe();
|
|
1904
2243
|
};
|
|
1905
|
-
}, [eventType
|
|
2244
|
+
}, [eventType]);
|
|
1906
2245
|
return lastEvent;
|
|
1907
2246
|
}
|
|
1908
2247
|
|
|
1909
|
-
|
|
2248
|
+
// src/hooks/useOutgoingInvites.ts
|
|
2249
|
+
function useOutgoingInvites() {
|
|
2250
|
+
return useRtcStore((state) => state.outgoingInvites);
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
// src/hooks/useInviteAccepted.ts
|
|
2254
|
+
function useInviteAccepted() {
|
|
2255
|
+
return useRtcStore((state) => {
|
|
2256
|
+
return Object.values(state.outgoingInvites).some(
|
|
2257
|
+
(invite) => invite.status === "accepted"
|
|
2258
|
+
);
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// src/hooks/useCallInitiated.ts
|
|
2263
|
+
function useCallInitiated() {
|
|
2264
|
+
return useRtcStore((state) => state.initiated);
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
// src/hooks/useSessionDuration.ts
|
|
2268
|
+
function useSessionDuration() {
|
|
2269
|
+
return 0;
|
|
2270
|
+
}
|
|
2271
|
+
var defaultRoomOptions = {
|
|
2272
|
+
adaptiveStream: true,
|
|
2273
|
+
dynacast: true
|
|
2274
|
+
};
|
|
2275
|
+
function useRoom(options) {
|
|
2276
|
+
const [room] = useState(() => new Room(options || defaultRoomOptions));
|
|
2277
|
+
const livekitInfo = useRtcStore((state) => state.session?.livekitInfo);
|
|
2278
|
+
useEffect(() => {
|
|
2279
|
+
if (!livekitInfo) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
room.connect(livekitInfo.url, livekitInfo.token);
|
|
2283
|
+
return () => {
|
|
2284
|
+
room.disconnect();
|
|
2285
|
+
};
|
|
2286
|
+
}, [livekitInfo, room]);
|
|
2287
|
+
if (!livekitInfo) {
|
|
2288
|
+
return null;
|
|
2289
|
+
}
|
|
2290
|
+
return room;
|
|
2291
|
+
}
|
|
2292
|
+
function useParticipantMetadata(participantOrIdentity) {
|
|
2293
|
+
const room = useRoom();
|
|
2294
|
+
const participants = useParticipants(room ? { room } : {});
|
|
2295
|
+
let resolvedParticipant;
|
|
2296
|
+
if (typeof participantOrIdentity === "string") {
|
|
2297
|
+
resolvedParticipant = participants.find(
|
|
2298
|
+
(p) => p.identity === participantOrIdentity
|
|
2299
|
+
);
|
|
2300
|
+
} else if (participantOrIdentity) {
|
|
2301
|
+
resolvedParticipant = participantOrIdentity;
|
|
2302
|
+
}
|
|
2303
|
+
const livekitInfo = useParticipantInfo(
|
|
2304
|
+
resolvedParticipant ? { participant: resolvedParticipant } : {}
|
|
2305
|
+
);
|
|
2306
|
+
if (!livekitInfo.metadata) {
|
|
2307
|
+
return null;
|
|
2308
|
+
}
|
|
2309
|
+
try {
|
|
2310
|
+
const metadata = JSON.parse(livekitInfo.metadata);
|
|
2311
|
+
if (!metadata.userId || !metadata.role) {
|
|
2312
|
+
console.warn("Invalid participant metadata: missing required fields", metadata);
|
|
2313
|
+
return null;
|
|
2314
|
+
}
|
|
2315
|
+
return {
|
|
2316
|
+
userId: metadata.userId,
|
|
2317
|
+
role: metadata.role,
|
|
2318
|
+
firstName: metadata.firstName || "",
|
|
2319
|
+
lastName: metadata.lastName || "",
|
|
2320
|
+
username: metadata.username || "",
|
|
2321
|
+
email: metadata.email || "",
|
|
2322
|
+
profilePhoto: metadata.profilePhoto || ""
|
|
2323
|
+
};
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
console.error("Failed to parse participant metadata:", error);
|
|
2326
|
+
return null;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
export { RtcProvider, SdkEventType, apiConfig, callCancelledSchema, callCreatedSchema, callEndedSchema, callInviteAcceptedSchema, callInviteCancelledSchema, callInviteDeclinedSchema, callInviteMissedSchema, callInviteSchema, callInviteSentSchema, callJoinInfoSchema, callMissedSchema, callParticipantAddedSchema, clearErrors, eventBus, pushApiError, pushDeviceError, pushError, pushIdentityGuardError, pushLiveKitConnectError, pushMediaPermissionError, pushNetworkError, pushSocketValidationError, pushStaleEventError, useCallActions, useCallInitiated, useCallState, useEvent, useIncomingInvite, useInviteAccepted, useOutgoingInvites, useParticipantMetadata, useRoom, useSdk, useSessionDuration, useSessionId };
|
|
1910
2331
|
//# sourceMappingURL=index.mjs.map
|
|
1911
2332
|
//# sourceMappingURL=index.mjs.map
|