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