@ai-matrx/meet 0.11.28 → 0.11.29
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/CHANGELOG.md +6 -0
- package/dist/{collab-CUxjUtrb.d.cts → collab-XY6Xj1dG.d.cts} +5 -0
- package/dist/{collab-CUxjUtrb.d.ts → collab-XY6Xj1dG.d.ts} +5 -0
- package/dist/{components-DPdU3POT.d.cts → components-4f9Mf8fz.d.cts} +1 -1
- package/dist/{components-CUPzD0y3.d.ts → components-Cwep2NYU.d.ts} +1 -1
- package/dist/core.cjs +488 -15
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +364 -165
- package/dist/core.d.ts +364 -165
- package/dist/core.js +488 -15
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +488 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +488 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +509 -20
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -4
- package/dist/react.d.ts +6 -4
- package/dist/react.js +509 -20
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +13 -5
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.d.cts +2 -2
- package/dist/skins/meet.d.ts +2 -2
- package/dist/skins/meet.js +13 -5
- package/dist/skins/meet.js.map +1 -1
- package/package.json +2 -2
package/dist/react.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(react_exports, {
|
|
|
38
38
|
CAPTION_LANGUAGES: () => CAPTION_LANGUAGES,
|
|
39
39
|
CONSENT_NOTICE_ATTRIBUTE: () => CONSENT_NOTICE_ATTRIBUTE,
|
|
40
40
|
DATA_TOPICS: () => DATA_TOPICS,
|
|
41
|
+
DEFAULT_CONNECTION_POLICY: () => DEFAULT_CONNECTION_POLICY,
|
|
41
42
|
DEFAULT_EFFECTS: () => DEFAULT_EFFECTS,
|
|
42
43
|
DEFAULT_PAGE_SIZE: () => DEFAULT_PAGE_SIZE,
|
|
43
44
|
EMPTY_COLLAB: () => EMPTY_COLLAB,
|
|
@@ -55,6 +56,7 @@ __export(react_exports, {
|
|
|
55
56
|
IncomingCallHost: () => IncomingCallHost,
|
|
56
57
|
JOIN_REFUSAL_REASONS: () => JOIN_REFUSAL_REASONS,
|
|
57
58
|
LISTEN_ONLY_NOTICE: () => LISTEN_ONLY_NOTICE,
|
|
59
|
+
LIVEKIT_BASE_DELAYS_MS: () => LIVEKIT_BASE_DELAYS_MS,
|
|
58
60
|
LIVE_PHASES: () => LIVE_PHASES,
|
|
59
61
|
MEETING_INVITE_KIND: () => MEETING_INVITE_KIND,
|
|
60
62
|
MEETING_INVITE_VERSION: () => MEETING_INVITE_VERSION,
|
|
@@ -84,6 +86,7 @@ __export(react_exports, {
|
|
|
84
86
|
PARTICIPANT_STANDING_ATTRIBUTE: () => PARTICIPANT_STANDING_ATTRIBUTE,
|
|
85
87
|
REACTION_TTL_MS: () => REACTION_TTL_MS,
|
|
86
88
|
REFUSED_ABSENCE: () => REFUSED_ABSENCE,
|
|
89
|
+
RESUME_WINDOW_MS: () => RESUME_WINDOW_MS,
|
|
87
90
|
ROLE_RANK: () => ROLE_RANK,
|
|
88
91
|
ROOM_EVENTS: () => ROOM_EVENTS,
|
|
89
92
|
ROOM_EVENT_PREFIX: () => ROOM_EVENT_PREFIX,
|
|
@@ -114,6 +117,7 @@ __export(react_exports, {
|
|
|
114
117
|
attendanceTotals: () => attendanceTotals,
|
|
115
118
|
attendeeKey: () => attendeeKey,
|
|
116
119
|
autoAssign: () => autoAssign,
|
|
120
|
+
autoRejoinDelayMs: () => autoRejoinDelayMs,
|
|
117
121
|
availableActivities: () => availableActivities,
|
|
118
122
|
breakoutRemainingMs: () => breakoutRemainingMs,
|
|
119
123
|
callInviteAction: () => callInviteAction,
|
|
@@ -128,9 +132,11 @@ __export(react_exports, {
|
|
|
128
132
|
clockPosition: () => clockPosition,
|
|
129
133
|
collabFromState: () => collabFromState,
|
|
130
134
|
computeStage: () => computeStage,
|
|
135
|
+
connectionPolicyFrom: () => connectionPolicyFrom,
|
|
131
136
|
countLabel: () => countLabel,
|
|
132
137
|
createCallCenter: () => createCallCenter,
|
|
133
138
|
createCallInviteHandler: () => createCallInviteHandler,
|
|
139
|
+
createConnectionSupervisor: () => createConnectionSupervisor,
|
|
134
140
|
createDeviceManager: () => createDeviceManager,
|
|
135
141
|
createInRoomClient: () => createInRoomClient,
|
|
136
142
|
createLiveKitDriver: () => createLiveKitDriver,
|
|
@@ -142,11 +148,15 @@ __export(react_exports, {
|
|
|
142
148
|
createMeetingRecordCache: () => createMeetingRecordCache,
|
|
143
149
|
createMeetingSession: () => createMeetingSession,
|
|
144
150
|
createMemoryDeviceStorage: () => createMemoryDeviceStorage,
|
|
151
|
+
createReachabilityProbe: () => createReachabilityProbe,
|
|
152
|
+
createReconnectPolicy: () => createReconnectPolicy,
|
|
145
153
|
createRecordingController: () => createRecordingController,
|
|
146
154
|
createRoomEngine: () => createRoomEngine,
|
|
147
155
|
createTokenClient: () => createTokenClient,
|
|
148
156
|
createWebDeviceStorage: () => createWebDeviceStorage,
|
|
149
157
|
createWebEffectsStorage: () => createWebEffectsStorage,
|
|
158
|
+
createWebNetworkPort: () => createWebNetworkPort,
|
|
159
|
+
createWebResumeStorage: () => createWebResumeStorage,
|
|
150
160
|
createWebRoomTokenStorage: () => createWebRoomTokenStorage,
|
|
151
161
|
defaultCaptionLanguage: () => defaultCaptionLanguage,
|
|
152
162
|
displayNameFor: () => displayNameFor,
|
|
@@ -159,6 +169,7 @@ __export(react_exports, {
|
|
|
159
169
|
guestRecordAccessSetting: () => guestRecordAccessSetting,
|
|
160
170
|
hasEnded: () => hasEnded,
|
|
161
171
|
hostUserIds: () => hostUserIds,
|
|
172
|
+
httpUrlOf: () => httpUrlOf,
|
|
162
173
|
invalidResponse: () => invalidResponse,
|
|
163
174
|
isGuest: () => isGuest,
|
|
164
175
|
isGuestIdentity: () => isGuestIdentity,
|
|
@@ -172,6 +183,7 @@ __export(react_exports, {
|
|
|
172
183
|
isRealName: () => isRealName,
|
|
173
184
|
isRefusedPhase: () => isRefusedPhase,
|
|
174
185
|
isRoomEventTopic: () => isRoomEventTopic,
|
|
186
|
+
isUnannouncedDeparture: () => isUnannouncedDeparture,
|
|
175
187
|
isWaitingPhase: () => isWaitingPhase,
|
|
176
188
|
learnName: () => learnName,
|
|
177
189
|
learnNames: () => learnNames,
|
|
@@ -194,6 +206,7 @@ __export(react_exports, {
|
|
|
194
206
|
meetingTopic: () => meetingTopic,
|
|
195
207
|
meetingWhen: () => meetingWhen,
|
|
196
208
|
mergeCaption: () => mergeCaption,
|
|
209
|
+
mergeGhosts: () => mergeGhosts,
|
|
197
210
|
mergeRecord: () => mergeRecord,
|
|
198
211
|
microphoneNoticeCode: () => microphoneNoticeCode,
|
|
199
212
|
moveToRoom: () => moveToRoom,
|
|
@@ -307,6 +320,352 @@ __export(react_exports, {
|
|
|
307
320
|
});
|
|
308
321
|
module.exports = __toCommonJS(react_exports);
|
|
309
322
|
|
|
323
|
+
// src/core/connection-supervisor.ts
|
|
324
|
+
var DEFAULT_CONNECTION_POLICY = {
|
|
325
|
+
bannerDelayMs: 2e3,
|
|
326
|
+
autoRejoin: true,
|
|
327
|
+
autoRejoinMaxAttempts: 5,
|
|
328
|
+
reconnectGraceSeconds: 30
|
|
329
|
+
};
|
|
330
|
+
function clampInt(value, min, max, fallback) {
|
|
331
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
332
|
+
return Math.min(max, Math.max(min, Math.round(value)));
|
|
333
|
+
}
|
|
334
|
+
function connectionPolicyFrom(raw) {
|
|
335
|
+
if (typeof raw !== "object" || raw === null) return DEFAULT_CONNECTION_POLICY;
|
|
336
|
+
const row = raw;
|
|
337
|
+
const d = DEFAULT_CONNECTION_POLICY;
|
|
338
|
+
return {
|
|
339
|
+
bannerDelayMs: clampInt(row["reconnect_banner_delay_ms"], 0, 1e4, d.bannerDelayMs),
|
|
340
|
+
autoRejoin: typeof row["auto_rejoin"] === "boolean" ? row["auto_rejoin"] : d.autoRejoin,
|
|
341
|
+
autoRejoinMaxAttempts: clampInt(row["auto_rejoin_max_attempts"], 0, 20, d.autoRejoinMaxAttempts),
|
|
342
|
+
reconnectGraceSeconds: clampInt(row["reconnect_grace_seconds"], 0, 600, d.reconnectGraceSeconds)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
var LIVEKIT_BASE_DELAYS_MS = [0, 300, 1200, 2700, 4800, 7e3];
|
|
346
|
+
function createReconnectPolicy(options = {}) {
|
|
347
|
+
const delays = options.delaysMs !== void 0 && options.delaysMs.length > 0 ? options.delaysMs : LIVEKIT_BASE_DELAYS_MS;
|
|
348
|
+
const giveUpMs = options.giveUpMs ?? 45e3;
|
|
349
|
+
const maxAttempts = options.maxAttempts ?? 12;
|
|
350
|
+
const random = options.random ?? Math.random;
|
|
351
|
+
return {
|
|
352
|
+
nextRetryDelayInMs({ retryCount, elapsedMs }) {
|
|
353
|
+
if (retryCount >= maxAttempts || elapsedMs >= giveUpMs) return null;
|
|
354
|
+
const base = delays[Math.min(retryCount, delays.length - 1)] ?? 0;
|
|
355
|
+
const spread = Math.min(2e3, Math.max(500, base / 2));
|
|
356
|
+
return Math.round(base + random() * spread);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function createWebNetworkPort() {
|
|
361
|
+
const scope = globalThis;
|
|
362
|
+
return {
|
|
363
|
+
online: () => scope.navigator?.onLine !== false,
|
|
364
|
+
subscribe(listener) {
|
|
365
|
+
if (typeof scope.addEventListener !== "function") return () => void 0;
|
|
366
|
+
const on = () => listener(true);
|
|
367
|
+
const off = () => listener(false);
|
|
368
|
+
scope.addEventListener("online", on);
|
|
369
|
+
scope.addEventListener("offline", off);
|
|
370
|
+
return () => {
|
|
371
|
+
scope.removeEventListener?.("online", on);
|
|
372
|
+
scope.removeEventListener?.("offline", off);
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function createReachabilityProbe(urls, timeoutMs = 4e3) {
|
|
378
|
+
return async () => {
|
|
379
|
+
const targets = urls().filter((url) => url.length > 0);
|
|
380
|
+
if (targets.length === 0 || typeof fetch !== "function") return true;
|
|
381
|
+
const one = async (url) => {
|
|
382
|
+
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
|
383
|
+
const timer = setTimeout(() => controller?.abort(), timeoutMs);
|
|
384
|
+
try {
|
|
385
|
+
await fetch(url, {
|
|
386
|
+
method: "GET",
|
|
387
|
+
mode: "no-cors",
|
|
388
|
+
cache: "no-store",
|
|
389
|
+
credentials: "omit",
|
|
390
|
+
...controller !== null ? { signal: controller.signal } : {}
|
|
391
|
+
});
|
|
392
|
+
return true;
|
|
393
|
+
} catch {
|
|
394
|
+
return false;
|
|
395
|
+
} finally {
|
|
396
|
+
clearTimeout(timer);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const answers = await Promise.all(targets.map(one));
|
|
400
|
+
return answers.every(Boolean);
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function httpUrlOf(serverUrl) {
|
|
404
|
+
return serverUrl.replace(/^ws(s?):\/\//i, "http$1://");
|
|
405
|
+
}
|
|
406
|
+
var RESUME_WINDOW_MS = 15 * 6e4;
|
|
407
|
+
var RESUME_KEY = "mx-meet:resume:";
|
|
408
|
+
function createWebResumeStorage() {
|
|
409
|
+
const storage = globalThis.sessionStorage;
|
|
410
|
+
if (storage === void 0) return void 0;
|
|
411
|
+
return {
|
|
412
|
+
load(roomName) {
|
|
413
|
+
try {
|
|
414
|
+
const raw = storage.getItem(RESUME_KEY + roomName);
|
|
415
|
+
if (raw === null) return null;
|
|
416
|
+
const parsed = JSON.parse(raw);
|
|
417
|
+
return typeof parsed?.at === "number" && typeof parsed.request?.roomName === "string" ? parsed : null;
|
|
418
|
+
} catch {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
save(roomName, marker) {
|
|
423
|
+
try {
|
|
424
|
+
storage.setItem(RESUME_KEY + roomName, JSON.stringify(marker));
|
|
425
|
+
} catch {
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
clear(roomName) {
|
|
429
|
+
try {
|
|
430
|
+
storage.removeItem(RESUME_KEY + roomName);
|
|
431
|
+
} catch {
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
var CLEARS_RESUME = (phase) => phase === "left" || phase === "removed" || phase === "superseded" || phase === "inactive" || phase === "ended" || phase === "record" || phase === "prejoin" || phase.startsWith("refused:") || phase.startsWith("waiting:");
|
|
437
|
+
function autoRejoinDelayMs(attempt, random = Math.random) {
|
|
438
|
+
const base = Math.min(15e3, 1e3 * 2 ** Math.max(0, attempt));
|
|
439
|
+
return Math.round(base * (0.5 + random()));
|
|
440
|
+
}
|
|
441
|
+
function createConnectionSupervisor(options) {
|
|
442
|
+
const { store, network } = options;
|
|
443
|
+
const now = options.now ?? (() => Date.now());
|
|
444
|
+
const random = options.random ?? Math.random;
|
|
445
|
+
const probeEveryMs = options.probeEveryMs ?? 3e3;
|
|
446
|
+
let driverRegion = null;
|
|
447
|
+
let probeTimer = null;
|
|
448
|
+
let probing = false;
|
|
449
|
+
let bannerTimer = null;
|
|
450
|
+
let rejoinTimer = null;
|
|
451
|
+
let rejoinAttempts = 0;
|
|
452
|
+
let lastPhase = store.snapshot().phase;
|
|
453
|
+
let lastSavedAt = 0;
|
|
454
|
+
let disposed = false;
|
|
455
|
+
const inCall = () => store.snapshot().phase === "in_call";
|
|
456
|
+
const dropped = () => store.snapshot().phase === "disconnected";
|
|
457
|
+
function setRegion(next) {
|
|
458
|
+
if (store.snapshot().connection !== next) store.patch({ connection: next });
|
|
459
|
+
}
|
|
460
|
+
function regionFor(reachable) {
|
|
461
|
+
if (!network.online()) return "offline";
|
|
462
|
+
if (reachable === false) return "server_unreachable";
|
|
463
|
+
if (dropped()) return reachable === true ? "stable" : store.snapshot().connection;
|
|
464
|
+
return driverRegion ?? "stable";
|
|
465
|
+
}
|
|
466
|
+
function needsWatch() {
|
|
467
|
+
const snap = store.snapshot();
|
|
468
|
+
if (dropped()) return true;
|
|
469
|
+
return inCall() && (driverRegion !== null || snap.connection !== "stable");
|
|
470
|
+
}
|
|
471
|
+
function stopProbe() {
|
|
472
|
+
if (probeTimer !== null) clearTimeout(probeTimer);
|
|
473
|
+
probeTimer = null;
|
|
474
|
+
}
|
|
475
|
+
function scheduleProbe(delayMs) {
|
|
476
|
+
if (disposed || probeTimer !== null) return;
|
|
477
|
+
probeTimer = setTimeout(() => {
|
|
478
|
+
probeTimer = null;
|
|
479
|
+
void runProbe();
|
|
480
|
+
}, delayMs);
|
|
481
|
+
}
|
|
482
|
+
async function runProbe() {
|
|
483
|
+
if (disposed || probing) return;
|
|
484
|
+
if (!needsWatch()) return;
|
|
485
|
+
if (!network.online()) {
|
|
486
|
+
setRegion("offline");
|
|
487
|
+
scheduleProbe(probeEveryMs);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
probing = true;
|
|
491
|
+
let reachable = false;
|
|
492
|
+
try {
|
|
493
|
+
reachable = await options.probe();
|
|
494
|
+
} catch {
|
|
495
|
+
reachable = false;
|
|
496
|
+
} finally {
|
|
497
|
+
probing = false;
|
|
498
|
+
}
|
|
499
|
+
if (disposed) return;
|
|
500
|
+
if (inCall() || dropped()) setRegion(regionFor(reachable));
|
|
501
|
+
if (dropped() && reachable) maybeRejoin();
|
|
502
|
+
if (needsWatch()) scheduleProbe(Math.round(probeEveryMs * (0.75 + random() * 0.5)));
|
|
503
|
+
}
|
|
504
|
+
function syncBanner() {
|
|
505
|
+
const snap = store.snapshot();
|
|
506
|
+
const unstable = snap.phase === "in_call" && snap.connection !== "stable";
|
|
507
|
+
if (!unstable) {
|
|
508
|
+
if (bannerTimer !== null) clearTimeout(bannerTimer);
|
|
509
|
+
bannerTimer = null;
|
|
510
|
+
if (snap.connectionBanner) store.patch({ connectionBanner: false });
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (snap.connectionBanner || bannerTimer !== null) return;
|
|
514
|
+
const delay = options.policy().bannerDelayMs;
|
|
515
|
+
if (delay <= 0) {
|
|
516
|
+
store.patch({ connectionBanner: true });
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
bannerTimer = setTimeout(() => {
|
|
520
|
+
bannerTimer = null;
|
|
521
|
+
const latest = store.snapshot();
|
|
522
|
+
if (latest.phase === "in_call" && latest.connection !== "stable" && !latest.connectionBanner) {
|
|
523
|
+
store.patch({ connectionBanner: true });
|
|
524
|
+
}
|
|
525
|
+
}, delay);
|
|
526
|
+
}
|
|
527
|
+
function stopRejoin() {
|
|
528
|
+
if (rejoinTimer !== null) clearTimeout(rejoinTimer);
|
|
529
|
+
rejoinTimer = null;
|
|
530
|
+
}
|
|
531
|
+
function maybeRejoin() {
|
|
532
|
+
if (disposed || rejoinTimer !== null || !dropped()) return;
|
|
533
|
+
const policy = options.policy();
|
|
534
|
+
if (!policy.autoRejoin) return;
|
|
535
|
+
if (rejoinAttempts >= policy.autoRejoinMaxAttempts) return;
|
|
536
|
+
if (!network.online()) return;
|
|
537
|
+
const attempt = rejoinAttempts;
|
|
538
|
+
rejoinTimer = setTimeout(() => {
|
|
539
|
+
rejoinTimer = null;
|
|
540
|
+
if (disposed || !dropped() || !network.online()) return;
|
|
541
|
+
rejoinAttempts = attempt + 1;
|
|
542
|
+
options.report?.("info", `meet: rejoining by itself (attempt ${rejoinAttempts} of ${policy.autoRejoinMaxAttempts})`);
|
|
543
|
+
void options.autoRejoin().catch(() => void 0);
|
|
544
|
+
}, autoRejoinDelayMs(attempt, random));
|
|
545
|
+
}
|
|
546
|
+
function saveMarker(force) {
|
|
547
|
+
const resume = options.resume;
|
|
548
|
+
const snap = store.snapshot();
|
|
549
|
+
if (resume === void 0 || snap.roomName === null) return;
|
|
550
|
+
const at = now();
|
|
551
|
+
if (!force && at - lastSavedAt < 1e4) return;
|
|
552
|
+
const request = options.currentRequest();
|
|
553
|
+
if (request === null) return;
|
|
554
|
+
lastSavedAt = at;
|
|
555
|
+
resume.save(snap.roomName, { request, at });
|
|
556
|
+
}
|
|
557
|
+
const unsubscribeStore = store.subscribe(() => {
|
|
558
|
+
if (disposed) return;
|
|
559
|
+
const snap = store.snapshot();
|
|
560
|
+
const phase = snap.phase;
|
|
561
|
+
const changed = phase !== lastPhase;
|
|
562
|
+
lastPhase = phase;
|
|
563
|
+
if (changed) {
|
|
564
|
+
if (phase === "in_call") {
|
|
565
|
+
rejoinAttempts = 0;
|
|
566
|
+
stopRejoin();
|
|
567
|
+
saveMarker(true);
|
|
568
|
+
} else if (phase === "disconnected") {
|
|
569
|
+
driverRegion = null;
|
|
570
|
+
saveMarker(true);
|
|
571
|
+
stopProbe();
|
|
572
|
+
scheduleProbe(0);
|
|
573
|
+
} else {
|
|
574
|
+
stopRejoin();
|
|
575
|
+
if (phase !== "joining") driverRegion = null;
|
|
576
|
+
if (CLEARS_RESUME(phase) && snap.roomName !== null) options.resume?.clear(snap.roomName);
|
|
577
|
+
}
|
|
578
|
+
} else if (phase === "in_call" || phase === "disconnected") {
|
|
579
|
+
saveMarker(false);
|
|
580
|
+
}
|
|
581
|
+
syncBanner();
|
|
582
|
+
});
|
|
583
|
+
const unsubscribeNetwork = network.subscribe((online) => {
|
|
584
|
+
if (disposed) return;
|
|
585
|
+
if (!online) {
|
|
586
|
+
if (inCall() || dropped()) setRegion("offline");
|
|
587
|
+
stopRejoin();
|
|
588
|
+
stopProbe();
|
|
589
|
+
if (needsWatch()) scheduleProbe(probeEveryMs);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
stopProbe();
|
|
593
|
+
if (needsWatch()) scheduleProbe(0);
|
|
594
|
+
});
|
|
595
|
+
return {
|
|
596
|
+
driverState(state) {
|
|
597
|
+
if (disposed) return;
|
|
598
|
+
if (state === "connected") {
|
|
599
|
+
driverRegion = null;
|
|
600
|
+
if (inCall() || store.snapshot().phase === "joining") setRegion(network.online() ? "stable" : "offline");
|
|
601
|
+
if (!needsWatch()) stopProbe();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (state === "reconnecting" || state === "signal_reconnecting") {
|
|
605
|
+
driverRegion = state;
|
|
606
|
+
if (inCall()) {
|
|
607
|
+
setRegion(network.online() ? state : "offline");
|
|
608
|
+
stopProbe();
|
|
609
|
+
scheduleProbe(0);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
exitConnection() {
|
|
614
|
+
return network.online() ? "server_unreachable" : "offline";
|
|
615
|
+
},
|
|
616
|
+
resumable(roomName) {
|
|
617
|
+
const resume = options.resume;
|
|
618
|
+
if (resume === void 0) return null;
|
|
619
|
+
const marker = resume.load(roomName);
|
|
620
|
+
if (marker === null) return null;
|
|
621
|
+
if (now() - marker.at > RESUME_WINDOW_MS) {
|
|
622
|
+
resume.clear(roomName);
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
return marker;
|
|
626
|
+
},
|
|
627
|
+
dispose() {
|
|
628
|
+
disposed = true;
|
|
629
|
+
stopProbe();
|
|
630
|
+
stopRejoin();
|
|
631
|
+
if (bannerTimer !== null) clearTimeout(bannerTimer);
|
|
632
|
+
bannerTimer = null;
|
|
633
|
+
unsubscribeStore();
|
|
634
|
+
unsubscribeNetwork();
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
var DELIBERATE_DEPARTURES = /* @__PURE__ */ new Set([
|
|
639
|
+
"CLIENT_INITIATED",
|
|
640
|
+
"PARTICIPANT_REMOVED",
|
|
641
|
+
"ROOM_DELETED",
|
|
642
|
+
"ROOM_CLOSED",
|
|
643
|
+
"DUPLICATE_IDENTITY",
|
|
644
|
+
"USER_REJECTED",
|
|
645
|
+
"USER_UNAVAILABLE",
|
|
646
|
+
"SIP_TRUNK_FAILURE"
|
|
647
|
+
]);
|
|
648
|
+
function isUnannouncedDeparture(reason) {
|
|
649
|
+
return reason === null || !DELIBERATE_DEPARTURES.has(reason);
|
|
650
|
+
}
|
|
651
|
+
function mergeGhosts(live, ghosts, at) {
|
|
652
|
+
const present = new Set(live.map((p) => p.identity));
|
|
653
|
+
const kept = /* @__PURE__ */ new Map();
|
|
654
|
+
const extra = [];
|
|
655
|
+
for (const [identity, ghost] of ghosts) {
|
|
656
|
+
if (present.has(identity) || ghost.until <= at) continue;
|
|
657
|
+
kept.set(identity, ghost);
|
|
658
|
+
extra.push({
|
|
659
|
+
...ghost.participant,
|
|
660
|
+
micEnabled: false,
|
|
661
|
+
cameraEnabled: false,
|
|
662
|
+
screenSharing: false,
|
|
663
|
+
reconnecting: true
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
return { roster: [...live, ...extra], kept };
|
|
667
|
+
}
|
|
668
|
+
|
|
310
669
|
// src/react/provider.tsx
|
|
311
670
|
var import_global_slot2 = require("@ai-matrx/kit/global-slot");
|
|
312
671
|
var import_react = require("react");
|
|
@@ -703,7 +1062,8 @@ function parseRoomToken(body, roomName) {
|
|
|
703
1062
|
admissionState: readString(payload, "admission_state") ?? void 0,
|
|
704
1063
|
pollSeconds: typeof payload["poll_seconds"] === "number" ? payload["poll_seconds"] : void 0,
|
|
705
1064
|
breakoutRoomId: readString(payload, "breakout_room_id") ?? null,
|
|
706
|
-
observersVisibleTo: readString(payload, "observers_visible_to") === "hosts" ? "hosts" : "everyone"
|
|
1065
|
+
observersVisibleTo: readString(payload, "observers_visible_to") === "hosts" ? "hosts" : "everyone",
|
|
1066
|
+
connectionPolicy: connectionPolicyFrom(payload["connection_policy"])
|
|
707
1067
|
};
|
|
708
1068
|
}
|
|
709
1069
|
function createTokenClient(options) {
|
|
@@ -1408,6 +1768,10 @@ function nextPhase(from, event) {
|
|
|
1408
1768
|
return from === "resolving" && event.reason !== null && isJoinRefusalReason(event.reason) ? refusalPhase(event.reason) : null;
|
|
1409
1769
|
case "join":
|
|
1410
1770
|
return JOINABLE_FROM.has(from) ? "joining" : null;
|
|
1771
|
+
case "auto_rejoin":
|
|
1772
|
+
return from === "disconnected" ? "joining" : null;
|
|
1773
|
+
case "resumed":
|
|
1774
|
+
return from === "resolving" ? "joining" : null;
|
|
1411
1775
|
case "back_to_prejoin":
|
|
1412
1776
|
return from === "left" || from === "disconnected" ? "prejoin" : null;
|
|
1413
1777
|
case "retry":
|
|
@@ -3547,6 +3911,7 @@ var EMPTY = {
|
|
|
3547
3911
|
phaseNotice: null,
|
|
3548
3912
|
roomName: null,
|
|
3549
3913
|
connection: "stable",
|
|
3914
|
+
connectionBanner: false,
|
|
3550
3915
|
share: NO_SHARE,
|
|
3551
3916
|
call: null,
|
|
3552
3917
|
waiting: null,
|
|
@@ -4826,6 +5191,18 @@ function createRoomEngine(options) {
|
|
|
4826
5191
|
let disposed = false;
|
|
4827
5192
|
let moving = false;
|
|
4828
5193
|
const confirmingEnds = /* @__PURE__ */ new WeakSet();
|
|
5194
|
+
let lastServerUrl = null;
|
|
5195
|
+
let connectionPolicy = DEFAULT_CONNECTION_POLICY;
|
|
5196
|
+
let ghosts = /* @__PURE__ */ new Map();
|
|
5197
|
+
let ghostTimer = null;
|
|
5198
|
+
let liveRoster = [];
|
|
5199
|
+
const departures = /* @__PURE__ */ new Map();
|
|
5200
|
+
function requestAsNow() {
|
|
5201
|
+
if (lastRequest === null) return null;
|
|
5202
|
+
const media = store.snapshot().media;
|
|
5203
|
+
if (store.snapshot().phase !== "in_call") return lastRequest;
|
|
5204
|
+
return { ...lastRequest, mode: media.camera.enabled ? "video" : "audio", microphone: media.microphone.enabled };
|
|
5205
|
+
}
|
|
4829
5206
|
async function dropRoom() {
|
|
4830
5207
|
const target = driver;
|
|
4831
5208
|
driver = null;
|
|
@@ -4836,6 +5213,7 @@ function createRoomEngine(options) {
|
|
|
4836
5213
|
store.setLocalTrack("microphone", IDLE_TRACK);
|
|
4837
5214
|
store.setLocalTrack("camera", IDLE_TRACK);
|
|
4838
5215
|
store.patch({ share: NO_SHARE, connection: "stable" });
|
|
5216
|
+
clearGhosts();
|
|
4839
5217
|
await target?.disconnect();
|
|
4840
5218
|
}
|
|
4841
5219
|
async function leaveRoom() {
|
|
@@ -4903,7 +5281,7 @@ function createRoomEngine(options) {
|
|
|
4903
5281
|
participants(list) {
|
|
4904
5282
|
const joinedAt = new Date(now()).toISOString();
|
|
4905
5283
|
const before = new Set(store.snapshot().participants.map((p) => p.identity));
|
|
4906
|
-
|
|
5284
|
+
projectRoster(list, joinedAt);
|
|
4907
5285
|
const snapshot = store.snapshot();
|
|
4908
5286
|
const newcomer = snapshot.participants.some(
|
|
4909
5287
|
(participant) => !participant.isLocal && !before.has(participant.identity)
|
|
@@ -4915,6 +5293,9 @@ function createRoomEngine(options) {
|
|
|
4915
5293
|
);
|
|
4916
5294
|
}
|
|
4917
5295
|
},
|
|
5296
|
+
participantLeft(who, reason) {
|
|
5297
|
+
departures.set(who, reason);
|
|
5298
|
+
},
|
|
4918
5299
|
roomMetadata(metadata) {
|
|
4919
5300
|
let spotlight = null;
|
|
4920
5301
|
if (metadata.length > 0) {
|
|
@@ -4941,12 +5322,8 @@ function createRoomEngine(options) {
|
|
|
4941
5322
|
store.setQuality(asParticipantIdentity(who), value);
|
|
4942
5323
|
},
|
|
4943
5324
|
connectionState(state) {
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
store.dispatch({ type: "connected" });
|
|
4947
|
-
} else if (state === "reconnecting") {
|
|
4948
|
-
store.patch({ connection: "reconnecting" });
|
|
4949
|
-
}
|
|
5325
|
+
supervisor.driverState(state);
|
|
5326
|
+
if (state === "connected" && store.snapshot().phase === "joining") store.dispatch({ type: "connected" });
|
|
4950
5327
|
},
|
|
4951
5328
|
transcription(event) {
|
|
4952
5329
|
const snapshot = store.snapshot();
|
|
@@ -5079,6 +5456,7 @@ function createRoomEngine(options) {
|
|
|
5079
5456
|
};
|
|
5080
5457
|
async function resolveExitAndApply(hint) {
|
|
5081
5458
|
const connection = current?.identity ?? store.snapshot().localIdentity ?? null;
|
|
5459
|
+
lastRequest = requestAsNow();
|
|
5082
5460
|
await dropRoom();
|
|
5083
5461
|
let server;
|
|
5084
5462
|
if (options.readExit === void 0 || connection === null || store.snapshot().meeting === null) {
|
|
@@ -5092,7 +5470,7 @@ function createRoomEngine(options) {
|
|
|
5092
5470
|
}
|
|
5093
5471
|
if (disposed) return;
|
|
5094
5472
|
const resolved = resolveExit({ server, hint, frozen: options.wasFrozen?.() ?? false });
|
|
5095
|
-
store.patch({ connection: resolved.connection });
|
|
5473
|
+
store.patch({ connection: server === null ? supervisor.exitConnection() : resolved.connection });
|
|
5096
5474
|
if (resolved.to === "waiting:knocking") {
|
|
5097
5475
|
store.patch({
|
|
5098
5476
|
waiting: {
|
|
@@ -5124,6 +5502,8 @@ function createRoomEngine(options) {
|
|
|
5124
5502
|
...request.observe === true ? { observe: true } : {}
|
|
5125
5503
|
});
|
|
5126
5504
|
current = token;
|
|
5505
|
+
lastServerUrl = token.serverUrl;
|
|
5506
|
+
connectionPolicy = token.connectionPolicy ?? DEFAULT_CONNECTION_POLICY;
|
|
5127
5507
|
store.patch({
|
|
5128
5508
|
localIdentity: token.identity,
|
|
5129
5509
|
breakoutRoomId: token.breakoutRoomId ?? null,
|
|
@@ -5228,7 +5608,59 @@ function createRoomEngine(options) {
|
|
|
5228
5608
|
throw normalized;
|
|
5229
5609
|
}
|
|
5230
5610
|
}
|
|
5231
|
-
|
|
5611
|
+
function projectRoster(list, joinedAt) {
|
|
5612
|
+
const at = now();
|
|
5613
|
+
const previous = new Map(liveRoster.map((p) => [p.identity, p]));
|
|
5614
|
+
const present = new Set(list.map((p) => p.identity));
|
|
5615
|
+
const graceMs = connectionPolicy.reconnectGraceSeconds * 1e3;
|
|
5616
|
+
for (const [who, reason] of departures) {
|
|
5617
|
+
const last = previous.get(who);
|
|
5618
|
+
if (last !== void 0 && !last.isLocal && !present.has(who) && graceMs > 0 && isUnannouncedDeparture(reason)) {
|
|
5619
|
+
ghosts.set(who, { participant: last, until: at + graceMs });
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
departures.clear();
|
|
5623
|
+
liveRoster = list;
|
|
5624
|
+
const merged = mergeGhosts(list, ghosts, at);
|
|
5625
|
+
ghosts = merged.kept;
|
|
5626
|
+
store.setParticipants(
|
|
5627
|
+
merged.roster.map((entry) => {
|
|
5628
|
+
const projected = projectParticipant(entry, joinedAt);
|
|
5629
|
+
return entry.reconnecting === true ? { ...projected, reconnecting: true, quality: "lost" } : projected;
|
|
5630
|
+
})
|
|
5631
|
+
);
|
|
5632
|
+
scheduleGhostExpiry();
|
|
5633
|
+
}
|
|
5634
|
+
function scheduleGhostExpiry() {
|
|
5635
|
+
if (ghostTimer !== null) clearTimeout(ghostTimer);
|
|
5636
|
+
ghostTimer = null;
|
|
5637
|
+
if (ghosts.size === 0 || disposed) return;
|
|
5638
|
+
const next = Math.min(...[...ghosts.values()].map((g) => g.until));
|
|
5639
|
+
ghostTimer = setTimeout(() => {
|
|
5640
|
+
ghostTimer = null;
|
|
5641
|
+
if (disposed || driver === null) return;
|
|
5642
|
+
projectRoster(liveRoster, new Date(now()).toISOString());
|
|
5643
|
+
}, Math.max(0, next - now()) + 50);
|
|
5644
|
+
}
|
|
5645
|
+
function clearGhosts() {
|
|
5646
|
+
ghosts = /* @__PURE__ */ new Map();
|
|
5647
|
+
departures.clear();
|
|
5648
|
+
liveRoster = [];
|
|
5649
|
+
if (ghostTimer !== null) clearTimeout(ghostTimer);
|
|
5650
|
+
ghostTimer = null;
|
|
5651
|
+
}
|
|
5652
|
+
const supervisor = createConnectionSupervisor({
|
|
5653
|
+
store,
|
|
5654
|
+
network: options.connection?.network ?? createWebNetworkPort(),
|
|
5655
|
+
probe: () => options.connection?.probe?.(current?.serverUrl ?? lastServerUrl) ?? Promise.resolve(true),
|
|
5656
|
+
policy: () => connectionPolicy,
|
|
5657
|
+
autoRejoin: () => engine.autoRejoin(),
|
|
5658
|
+
currentRequest: requestAsNow,
|
|
5659
|
+
resume: options.connection?.resume,
|
|
5660
|
+
now,
|
|
5661
|
+
report: (level, message) => report(level, message)
|
|
5662
|
+
});
|
|
5663
|
+
const engine = {
|
|
5232
5664
|
join(request) {
|
|
5233
5665
|
if (joining !== null) return joining;
|
|
5234
5666
|
if (store.snapshot().phase !== "joining" && !store.dispatch({ type: "join", click: true })) {
|
|
@@ -5273,6 +5705,35 @@ function createRoomEngine(options) {
|
|
|
5273
5705
|
});
|
|
5274
5706
|
return joining;
|
|
5275
5707
|
},
|
|
5708
|
+
async autoRejoin() {
|
|
5709
|
+
const request = lastRequest;
|
|
5710
|
+
if (request === null || joining !== null) return joining ?? void 0;
|
|
5711
|
+
if (!store.dispatch({ type: "auto_rejoin" })) return;
|
|
5712
|
+
tokens.invalidate(request.roomName);
|
|
5713
|
+
current = null;
|
|
5714
|
+
joining = connect(request).catch((error) => {
|
|
5715
|
+
throw failJoin(error, "meet.autoRejoin");
|
|
5716
|
+
}).finally(() => {
|
|
5717
|
+
joining = null;
|
|
5718
|
+
});
|
|
5719
|
+
return joining;
|
|
5720
|
+
},
|
|
5721
|
+
resume(roomName) {
|
|
5722
|
+
const marker = supervisor.resumable(roomName);
|
|
5723
|
+
if (marker === null || joining !== null) return false;
|
|
5724
|
+
if (!store.dispatch({ type: "resumed" })) return false;
|
|
5725
|
+
lastRequest = { ...marker.request, roomName };
|
|
5726
|
+
report("info", "meet: this tab was in the call before the page reloaded \u2014 rejoining");
|
|
5727
|
+
tokens.invalidate(roomName);
|
|
5728
|
+
current = null;
|
|
5729
|
+
joining = connect(lastRequest).catch((error) => {
|
|
5730
|
+
throw failJoin(error, "meet.resume");
|
|
5731
|
+
}).finally(() => {
|
|
5732
|
+
joining = null;
|
|
5733
|
+
});
|
|
5734
|
+
joining.catch(() => void 0);
|
|
5735
|
+
return true;
|
|
5736
|
+
},
|
|
5276
5737
|
async moveToBreakout(roomId) {
|
|
5277
5738
|
const request = lastRequest;
|
|
5278
5739
|
if (request === null || driver === null) {
|
|
@@ -5440,6 +5901,8 @@ function createRoomEngine(options) {
|
|
|
5440
5901
|
token: () => current,
|
|
5441
5902
|
async dispose() {
|
|
5442
5903
|
disposed = true;
|
|
5904
|
+
supervisor.dispose();
|
|
5905
|
+
clearGhosts();
|
|
5443
5906
|
if (driver !== null) {
|
|
5444
5907
|
const target = driver;
|
|
5445
5908
|
driver = null;
|
|
@@ -5448,6 +5911,7 @@ function createRoomEngine(options) {
|
|
|
5448
5911
|
store.reset();
|
|
5449
5912
|
}
|
|
5450
5913
|
};
|
|
5914
|
+
return engine;
|
|
5451
5915
|
}
|
|
5452
5916
|
function canModerate(participant) {
|
|
5453
5917
|
return participant !== void 0 && isHostRole(participant.role);
|
|
@@ -5758,8 +6222,11 @@ function mapConnectionState(state) {
|
|
|
5758
6222
|
case "connecting":
|
|
5759
6223
|
return "connecting";
|
|
5760
6224
|
case "reconnecting":
|
|
5761
|
-
case "signalReconnecting":
|
|
5762
6225
|
return "reconnecting";
|
|
6226
|
+
// Only the signal socket is down (S6b): its own region value, so the supervisor can tell a
|
|
6227
|
+
// signal blip from a full media reconnect.
|
|
6228
|
+
case "signalReconnecting":
|
|
6229
|
+
return "signal_reconnecting";
|
|
5763
6230
|
default:
|
|
5764
6231
|
return "disconnected";
|
|
5765
6232
|
}
|
|
@@ -5840,8 +6307,12 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
5840
6307
|
// R5: large meetings degrade gracefully instead of melting a laptop.
|
|
5841
6308
|
adaptiveStream: true,
|
|
5842
6309
|
dynacast: true,
|
|
6310
|
+
// S6b: OUR retry schedule — jittered from attempt 0 (the SDK's default has no jitter on its
|
|
6311
|
+
// first two attempts), give-up limits in one place (`connection-supervisor.ts`).
|
|
6312
|
+
reconnectPolicy: createReconnectPolicy(),
|
|
5843
6313
|
...options.roomOptions
|
|
5844
6314
|
});
|
|
6315
|
+
const reasonName = (reason) => reason === void 0 || reason === null ? null : module2.DisconnectReason?.[reason] ?? String(reason);
|
|
5845
6316
|
const roster = () => {
|
|
5846
6317
|
const local = snapshotParticipant(created.localParticipant, true);
|
|
5847
6318
|
const remotes = [...created.remoteParticipants.values()].map(
|
|
@@ -5859,7 +6330,10 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
5859
6330
|
if (track.kind !== Track.Kind.Audio) return;
|
|
5860
6331
|
for (const element of track.detach()) element.remove();
|
|
5861
6332
|
});
|
|
5862
|
-
created.on(RoomEvent.ParticipantConnected, roster).on(RoomEvent.ParticipantDisconnected,
|
|
6333
|
+
created.on(RoomEvent.ParticipantConnected, roster).on(RoomEvent.ParticipantDisconnected, (participant, reason) => {
|
|
6334
|
+
handlers.participantLeft?.(participant.identity, reasonName(reason));
|
|
6335
|
+
roster();
|
|
6336
|
+
}).on(RoomEvent.TrackSubscribed, roster).on(RoomEvent.TrackUnsubscribed, roster).on(RoomEvent.TrackMuted, roster).on(RoomEvent.TrackUnmuted, roster).on(RoomEvent.LocalTrackPublished, roster).on(RoomEvent.LocalTrackUnpublished, roster).on(RoomEvent.ParticipantNameChanged, roster).on(RoomEvent.ParticipantAttributesChanged, roster).on(RoomEvent.ParticipantMetadataChanged, roster).on(RoomEvent.RoomMetadataChanged, (metadata) => {
|
|
5863
6337
|
handlers.roomMetadata?.(metadata ?? "");
|
|
5864
6338
|
}).on(RoomEvent.ActiveSpeakersChanged, (speakers) => {
|
|
5865
6339
|
handlers.activeSpeakers(speakers.map((speaker) => speaker.identity));
|
|
@@ -5876,8 +6350,7 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
5876
6350
|
}).on(RoomEvent.Disconnected, (reason) => {
|
|
5877
6351
|
audioContainer?.remove();
|
|
5878
6352
|
audioContainer = null;
|
|
5879
|
-
|
|
5880
|
-
handlers.disconnected(named);
|
|
6353
|
+
handlers.disconnected(reasonName(reason));
|
|
5881
6354
|
});
|
|
5882
6355
|
try {
|
|
5883
6356
|
created.registerTextStreamHandler(TRANSCRIPTION_TOPIC, (reader, participantInfo) => {
|
|
@@ -6267,7 +6740,14 @@ function MeetRuntime(props) {
|
|
|
6267
6740
|
effectsStorage,
|
|
6268
6741
|
resolveDevice: (kind) => devicesHolder.current?.resolve(kind) ?? null,
|
|
6269
6742
|
// §3.4: on every LiveKit disconnect, ask the server what happened to this connection.
|
|
6270
|
-
readExit: (connection) => meetings.readExit(connection)
|
|
6743
|
+
readExit: (connection) => meetings.readExit(connection),
|
|
6744
|
+
// S6b: the connection supervisor's ports — the device's network, whether OUR servers (the
|
|
6745
|
+
// API and the media server) answer, and the per-tab reload-after-offline marker.
|
|
6746
|
+
connection: {
|
|
6747
|
+
network: createWebNetworkPort(),
|
|
6748
|
+
resume: createWebResumeStorage(),
|
|
6749
|
+
probe: (serverUrl) => createReachabilityProbe(() => [baseUrl, ...serverUrl !== null ? [httpUrlOf(serverUrl)] : []])()
|
|
6750
|
+
}
|
|
6271
6751
|
});
|
|
6272
6752
|
const meetings = createMeetingSession({
|
|
6273
6753
|
manager,
|
|
@@ -6595,7 +7075,7 @@ function participantAttributes(p) {
|
|
|
6595
7075
|
"data-meet-participant-role": observedRole(p.role, p.standing),
|
|
6596
7076
|
"data-meet-participant-self": String(p.isLocal)
|
|
6597
7077
|
};
|
|
6598
|
-
const quality = observedQuality(p.quality);
|
|
7078
|
+
const quality = p.reconnecting === true ? "reconnecting" : observedQuality(p.quality);
|
|
6599
7079
|
if (quality !== null) attrs["data-meet-participant-connection"] = quality;
|
|
6600
7080
|
return attrs;
|
|
6601
7081
|
}
|
|
@@ -8814,6 +9294,7 @@ function useMeetCore() {
|
|
|
8814
9294
|
reason: snapshot?.reason ?? null,
|
|
8815
9295
|
phaseNotice: snapshot?.phaseNotice ?? null,
|
|
8816
9296
|
connection: snapshot?.connection ?? "stable",
|
|
9297
|
+
connectionBanner: snapshot?.connectionBanner ?? false,
|
|
8817
9298
|
share: snapshot?.share ?? NO_SHARE,
|
|
8818
9299
|
call: snapshot?.call ?? null,
|
|
8819
9300
|
actions
|
|
@@ -10080,7 +10561,8 @@ function ParticipantTile({
|
|
|
10080
10561
|
participant.displayName,
|
|
10081
10562
|
participant.isLocal ? " (you)" : "",
|
|
10082
10563
|
participant.isAgent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "AI" }) : null,
|
|
10083
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RoleBadge, { role: participant.role, standing: participant.standing })
|
|
10564
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RoleBadge, { role: participant.role, standing: participant.standing }),
|
|
10565
|
+
participant.reconnecting === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__badge", children: "Reconnecting\u2026" }) : null
|
|
10084
10566
|
] }),
|
|
10085
10567
|
!participant.micEnabled ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicOffIcon, { width: 14, height: 14 }) : null,
|
|
10086
10568
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QualityBars, { quality: participant.quality })
|
|
@@ -10123,6 +10605,12 @@ function QualityBars({ quality }) {
|
|
|
10123
10605
|
const label = quality === "lost" ? "Connection lost" : quality === "poor" ? "Poor connection" : `Connection ${quality}`;
|
|
10124
10606
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `mx-meet__signal mx-meet__signal--${quality}`, title: label, "aria-label": label, role: "img", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SignalIcon, { bars, width: 14, height: 14 }) });
|
|
10125
10607
|
}
|
|
10608
|
+
var CONNECTION_BANNER = {
|
|
10609
|
+
signal_reconnecting: "Reconnecting\u2026",
|
|
10610
|
+
reconnecting: "Reconnecting\u2026",
|
|
10611
|
+
offline: "You're offline. Reconnecting when your internet is back\u2026",
|
|
10612
|
+
server_unreachable: "Can't reach the meeting server. Retrying\u2026"
|
|
10613
|
+
};
|
|
10126
10614
|
function Stage({ pageSize }) {
|
|
10127
10615
|
const stage = useStage(pageSize);
|
|
10128
10616
|
const columns = gridColumns(stage.tiles.length);
|
|
@@ -11830,7 +12318,7 @@ function MeetSkinRoom({
|
|
|
11830
12318
|
headerControls !== void 0 && headerControls !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__header-controls", "data-meet-header-controls": "", children: headerControls }) : null,
|
|
11831
12319
|
isHost ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HostMenu, {}) : null
|
|
11832
12320
|
] }),
|
|
11833
|
-
core.connection !== "stable" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__banner", role: "status", children:
|
|
12321
|
+
core.connectionBanner && core.connection !== "stable" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": `connection-${core.connection}`, children: CONNECTION_BANNER[core.connection] }) : null,
|
|
11834
12322
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ShareNotice, {}),
|
|
11835
12323
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stage, {}),
|
|
11836
12324
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Captions, {}),
|
|
@@ -11864,7 +12352,7 @@ var REFUSED_TITLES = {
|
|
|
11864
12352
|
registration_required: "Register to join this meeting"
|
|
11865
12353
|
};
|
|
11866
12354
|
function ExitScreen({ onLeave }) {
|
|
11867
|
-
const { phase, reason, host, snapshot, actions, call } = useMeetCore();
|
|
12355
|
+
const { phase, reason, host, snapshot, actions, call, connection } = useMeetCore();
|
|
11868
12356
|
const [busy, setBusy] = (0, import_react10.useState)(false);
|
|
11869
12357
|
const failure = snapshot?.failure ?? null;
|
|
11870
12358
|
const rejoin = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -11920,7 +12408,7 @@ function ExitScreen({ onLeave }) {
|
|
|
11920
12408
|
break;
|
|
11921
12409
|
case "disconnected":
|
|
11922
12410
|
title = "You lost your connection to the meeting";
|
|
11923
|
-
line = failure?.remedy ?? "Check your internet connection, then rejoin.";
|
|
12411
|
+
line = connection === "offline" ? "You're offline. You'll rejoin automatically when your internet is back." : connection === "server_unreachable" ? "Can't reach the meeting server. You'll rejoin automatically when it answers." : failure?.remedy ?? "Check your internet connection, then rejoin.";
|
|
11924
12412
|
notice = "disconnected";
|
|
11925
12413
|
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11926
12414
|
rejoin,
|
|
@@ -12529,6 +13017,7 @@ function MeetingSkinRootBody({
|
|
|
12529
13017
|
host.store.dispatch({ type: "reset" });
|
|
12530
13018
|
}
|
|
12531
13019
|
if (host.store.snapshot().phase !== "resolving") return;
|
|
13020
|
+
if (given?.linkRun?.reason == null && host.engine.resume(roomName)) return;
|
|
12532
13021
|
const reason = given?.linkRun?.reason ?? null;
|
|
12533
13022
|
if (reason !== null && given?.linkRun !== void 0) {
|
|
12534
13023
|
const words = linkRunWords(given.linkRun);
|