@poolse/react 2.12.1 → 2.13.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/CHANGELOG.md +170 -149
- package/LICENSE +21 -21
- package/README.md +335 -335
- package/dist/index.cjs +45 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -2
- package/dist/index.d.ts +41 -2
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
|
|
2
|
+
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
|
|
3
3
|
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, Conversation, ConversationCreateRequest, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, RealtimeStatus, Uuid } from '@poolse/sdk';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
@@ -501,6 +501,14 @@ interface UseCallRoomOptions {
|
|
|
501
501
|
video?: boolean;
|
|
502
502
|
/** Join muted. */
|
|
503
503
|
muted?: boolean;
|
|
504
|
+
/** Which camera to open with. Defaults to the front one. */
|
|
505
|
+
facing?: CameraFacing;
|
|
506
|
+
/**
|
|
507
|
+
* How long the last participant may sit alone before {@link
|
|
508
|
+
* UseCallRoom.alone} turns true, in milliseconds. Defaults to 1500.
|
|
509
|
+
* Pass `0` to never report it.
|
|
510
|
+
*/
|
|
511
|
+
aloneGraceMs?: number;
|
|
504
512
|
}
|
|
505
513
|
interface UseCallRoom {
|
|
506
514
|
status: CallRoomStatus;
|
|
@@ -508,6 +516,22 @@ interface UseCallRoom {
|
|
|
508
516
|
participants: CallParticipant[];
|
|
509
517
|
cameraEnabled: boolean;
|
|
510
518
|
micEnabled: boolean;
|
|
519
|
+
/** Which camera is publishing. Meaningless while the camera is off. */
|
|
520
|
+
facingMode: CameraFacing;
|
|
521
|
+
/**
|
|
522
|
+
* Everyone else has gone and is not coming back.
|
|
523
|
+
*
|
|
524
|
+
* Turns true only after somebody else has actually been on the call,
|
|
525
|
+
* so the caller waiting for an answer never trips it. Wire it to your
|
|
526
|
+
* hang-up path — a peer whose app was killed or whose phone lost
|
|
527
|
+
* signal sends no `call:hangup`, and without this the survivor is
|
|
528
|
+
* left on a call screen that will never close on its own.
|
|
529
|
+
*
|
|
530
|
+
* useEffect(() => {
|
|
531
|
+
* if (media.alone) void calls.hangUp();
|
|
532
|
+
* }, [media.alone]);
|
|
533
|
+
*/
|
|
534
|
+
alone: boolean;
|
|
511
535
|
error: Error | null;
|
|
512
536
|
/**
|
|
513
537
|
* Whether this deployment has an SFU.
|
|
@@ -522,6 +546,8 @@ interface UseCallRoom {
|
|
|
522
546
|
leave: () => void;
|
|
523
547
|
setCameraEnabled: (enabled: boolean) => Promise<void>;
|
|
524
548
|
toggleCamera: () => Promise<void>;
|
|
549
|
+
/** Swap between the front and rear cameras. */
|
|
550
|
+
switchCamera: () => Promise<void>;
|
|
525
551
|
setMicrophoneEnabled: (enabled: boolean) => Promise<void>;
|
|
526
552
|
toggleMic: () => Promise<void>;
|
|
527
553
|
}
|
|
@@ -547,6 +573,16 @@ interface UseVoiceRoom {
|
|
|
547
573
|
/** Everyone currently in the room, oldest join first. */
|
|
548
574
|
participants: VoiceParticipant[];
|
|
549
575
|
muted: boolean;
|
|
576
|
+
/**
|
|
577
|
+
* Everyone else has left and is not coming back.
|
|
578
|
+
*
|
|
579
|
+
* The mesh equivalent of `useCallRoom`'s flag of the same name — see
|
|
580
|
+
* there for why a call needs this on top of the explicit hang-up
|
|
581
|
+
* signal. Only meaningful for a room being used to carry a call; a
|
|
582
|
+
* Discord-style room you sit in alone is a normal state, so wire this
|
|
583
|
+
* to hang-up only on the call surface.
|
|
584
|
+
*/
|
|
585
|
+
alone: boolean;
|
|
550
586
|
error: Error | null;
|
|
551
587
|
/** Acquire the mic and connect. Safe to call twice. */
|
|
552
588
|
join: () => Promise<void>;
|
|
@@ -566,7 +602,10 @@ interface UseVoiceRoom {
|
|
|
566
602
|
*
|
|
567
603
|
* For ringing someone who hasn't joined yet, see `useCalls`.
|
|
568
604
|
*/
|
|
569
|
-
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions
|
|
605
|
+
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions & {
|
|
606
|
+
/** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */
|
|
607
|
+
aloneGraceMs?: number;
|
|
608
|
+
}): UseVoiceRoom;
|
|
570
609
|
|
|
571
610
|
/** Where a call is in its lifecycle, from this device's point of view. */
|
|
572
611
|
type CallPhase = 'idle'
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
|
|
2
|
+
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, LiveKitModule, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall, CallMedia } from '@poolse/sdk';
|
|
3
3
|
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, Conversation, ConversationCreateRequest, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, RealtimeStatus, Uuid } from '@poolse/sdk';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
@@ -501,6 +501,14 @@ interface UseCallRoomOptions {
|
|
|
501
501
|
video?: boolean;
|
|
502
502
|
/** Join muted. */
|
|
503
503
|
muted?: boolean;
|
|
504
|
+
/** Which camera to open with. Defaults to the front one. */
|
|
505
|
+
facing?: CameraFacing;
|
|
506
|
+
/**
|
|
507
|
+
* How long the last participant may sit alone before {@link
|
|
508
|
+
* UseCallRoom.alone} turns true, in milliseconds. Defaults to 1500.
|
|
509
|
+
* Pass `0` to never report it.
|
|
510
|
+
*/
|
|
511
|
+
aloneGraceMs?: number;
|
|
504
512
|
}
|
|
505
513
|
interface UseCallRoom {
|
|
506
514
|
status: CallRoomStatus;
|
|
@@ -508,6 +516,22 @@ interface UseCallRoom {
|
|
|
508
516
|
participants: CallParticipant[];
|
|
509
517
|
cameraEnabled: boolean;
|
|
510
518
|
micEnabled: boolean;
|
|
519
|
+
/** Which camera is publishing. Meaningless while the camera is off. */
|
|
520
|
+
facingMode: CameraFacing;
|
|
521
|
+
/**
|
|
522
|
+
* Everyone else has gone and is not coming back.
|
|
523
|
+
*
|
|
524
|
+
* Turns true only after somebody else has actually been on the call,
|
|
525
|
+
* so the caller waiting for an answer never trips it. Wire it to your
|
|
526
|
+
* hang-up path — a peer whose app was killed or whose phone lost
|
|
527
|
+
* signal sends no `call:hangup`, and without this the survivor is
|
|
528
|
+
* left on a call screen that will never close on its own.
|
|
529
|
+
*
|
|
530
|
+
* useEffect(() => {
|
|
531
|
+
* if (media.alone) void calls.hangUp();
|
|
532
|
+
* }, [media.alone]);
|
|
533
|
+
*/
|
|
534
|
+
alone: boolean;
|
|
511
535
|
error: Error | null;
|
|
512
536
|
/**
|
|
513
537
|
* Whether this deployment has an SFU.
|
|
@@ -522,6 +546,8 @@ interface UseCallRoom {
|
|
|
522
546
|
leave: () => void;
|
|
523
547
|
setCameraEnabled: (enabled: boolean) => Promise<void>;
|
|
524
548
|
toggleCamera: () => Promise<void>;
|
|
549
|
+
/** Swap between the front and rear cameras. */
|
|
550
|
+
switchCamera: () => Promise<void>;
|
|
525
551
|
setMicrophoneEnabled: (enabled: boolean) => Promise<void>;
|
|
526
552
|
toggleMic: () => Promise<void>;
|
|
527
553
|
}
|
|
@@ -547,6 +573,16 @@ interface UseVoiceRoom {
|
|
|
547
573
|
/** Everyone currently in the room, oldest join first. */
|
|
548
574
|
participants: VoiceParticipant[];
|
|
549
575
|
muted: boolean;
|
|
576
|
+
/**
|
|
577
|
+
* Everyone else has left and is not coming back.
|
|
578
|
+
*
|
|
579
|
+
* The mesh equivalent of `useCallRoom`'s flag of the same name — see
|
|
580
|
+
* there for why a call needs this on top of the explicit hang-up
|
|
581
|
+
* signal. Only meaningful for a room being used to carry a call; a
|
|
582
|
+
* Discord-style room you sit in alone is a normal state, so wire this
|
|
583
|
+
* to hang-up only on the call surface.
|
|
584
|
+
*/
|
|
585
|
+
alone: boolean;
|
|
550
586
|
error: Error | null;
|
|
551
587
|
/** Acquire the mic and connect. Safe to call twice. */
|
|
552
588
|
join: () => Promise<void>;
|
|
@@ -566,7 +602,10 @@ interface UseVoiceRoom {
|
|
|
566
602
|
*
|
|
567
603
|
* For ringing someone who hasn't joined yet, see `useCalls`.
|
|
568
604
|
*/
|
|
569
|
-
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions
|
|
605
|
+
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions & {
|
|
606
|
+
/** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */
|
|
607
|
+
aloneGraceMs?: number;
|
|
608
|
+
}): UseVoiceRoom;
|
|
570
609
|
|
|
571
610
|
/** Where a call is in its lifecycle, from this device's point of view. */
|
|
572
611
|
type CallPhase = 'idle'
|
package/dist/index.js
CHANGED
|
@@ -1068,22 +1068,28 @@ function useCallRoom(conversationId, opts) {
|
|
|
1068
1068
|
const [participants, setParticipants] = useState([]);
|
|
1069
1069
|
const [cameraEnabled, setCamera] = useState(false);
|
|
1070
1070
|
const [micEnabled, setMic] = useState(false);
|
|
1071
|
+
const [facingMode, setFacing] = useState(opts.facing ?? "user");
|
|
1072
|
+
const [alone, setAlone] = useState(false);
|
|
1071
1073
|
const [error, setError] = useState(null);
|
|
1072
1074
|
const [sfuAvailable, setSfuAvailable] = useState(null);
|
|
1073
1075
|
const optsRef = useRef(opts);
|
|
1076
|
+
optsRef.current = opts;
|
|
1074
1077
|
const joined = useRef(false);
|
|
1075
1078
|
const room = useMemo(() => {
|
|
1076
1079
|
if (!conversationId) return null;
|
|
1077
1080
|
return poolse.call(conversationId, {
|
|
1078
1081
|
livekit: optsRef.current.livekit,
|
|
1079
1082
|
...optsRef.current.video !== void 0 ? { video: optsRef.current.video } : {},
|
|
1080
|
-
...optsRef.current.muted !== void 0 ? { muted: optsRef.current.muted } : {}
|
|
1083
|
+
...optsRef.current.muted !== void 0 ? { muted: optsRef.current.muted } : {},
|
|
1084
|
+
...optsRef.current.facing !== void 0 ? { facing: optsRef.current.facing } : {},
|
|
1085
|
+
...optsRef.current.aloneGraceMs !== void 0 ? { aloneGraceMs: optsRef.current.aloneGraceMs } : {}
|
|
1081
1086
|
});
|
|
1082
1087
|
}, [poolse, conversationId]);
|
|
1083
1088
|
const sync = useCallback((target) => {
|
|
1084
1089
|
if (!target) return;
|
|
1085
1090
|
setCamera(target.isCameraEnabled());
|
|
1086
1091
|
setMic(target.isMicrophoneEnabled());
|
|
1092
|
+
setFacing(target.getFacingMode());
|
|
1087
1093
|
}, []);
|
|
1088
1094
|
useEffect(() => {
|
|
1089
1095
|
if (!room) {
|
|
@@ -1093,15 +1099,18 @@ function useCallRoom(conversationId, opts) {
|
|
|
1093
1099
|
}
|
|
1094
1100
|
setStatus(room.getStatus());
|
|
1095
1101
|
setParticipants(room.getParticipants());
|
|
1102
|
+
setAlone(false);
|
|
1096
1103
|
const offStatus = room.onStatus(setStatus);
|
|
1097
1104
|
const offRoster = room.onParticipants((next) => {
|
|
1098
1105
|
setParticipants(next);
|
|
1099
1106
|
sync(room);
|
|
1100
1107
|
});
|
|
1108
|
+
const offAlone = room.onAlone(() => setAlone(true));
|
|
1101
1109
|
const offError = room.onError(setError);
|
|
1102
1110
|
return () => {
|
|
1103
1111
|
offStatus();
|
|
1104
1112
|
offRoster();
|
|
1113
|
+
offAlone();
|
|
1105
1114
|
offError();
|
|
1106
1115
|
if (joined.current) {
|
|
1107
1116
|
joined.current = false;
|
|
@@ -1153,21 +1162,50 @@ function useCallRoom(conversationId, opts) {
|
|
|
1153
1162
|
if (!room) return;
|
|
1154
1163
|
await setMicrophoneEnabled(!room.isMicrophoneEnabled());
|
|
1155
1164
|
}, [room, setMicrophoneEnabled]);
|
|
1165
|
+
const switchCamera = useCallback(async () => {
|
|
1166
|
+
if (!room) return;
|
|
1167
|
+
await room.switchCamera();
|
|
1168
|
+
setFacing(room.getFacingMode());
|
|
1169
|
+
}, [room]);
|
|
1156
1170
|
return {
|
|
1157
1171
|
status,
|
|
1158
1172
|
participants,
|
|
1159
1173
|
cameraEnabled,
|
|
1160
1174
|
micEnabled,
|
|
1175
|
+
facingMode,
|
|
1176
|
+
alone,
|
|
1161
1177
|
error,
|
|
1162
1178
|
sfuAvailable,
|
|
1163
1179
|
join,
|
|
1164
1180
|
leave,
|
|
1165
1181
|
setCameraEnabled,
|
|
1166
1182
|
toggleCamera,
|
|
1183
|
+
switchCamera,
|
|
1167
1184
|
setMicrophoneEnabled,
|
|
1168
1185
|
toggleMic
|
|
1169
1186
|
};
|
|
1170
1187
|
}
|
|
1188
|
+
function useAloneWatch({ active, others, graceMs }) {
|
|
1189
|
+
const [alone, setAlone] = useState(false);
|
|
1190
|
+
const seenPeer = useRef(false);
|
|
1191
|
+
useEffect(() => {
|
|
1192
|
+
if (!active) {
|
|
1193
|
+
seenPeer.current = false;
|
|
1194
|
+
setAlone(false);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
if (others > 0) {
|
|
1198
|
+
seenPeer.current = true;
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
if (graceMs <= 0 || !seenPeer.current) return;
|
|
1202
|
+
const timer = setTimeout(() => setAlone(true), graceMs);
|
|
1203
|
+
return () => clearTimeout(timer);
|
|
1204
|
+
}, [active, others, graceMs]);
|
|
1205
|
+
return alone;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// src/use-voice-room.ts
|
|
1171
1209
|
function useVoiceRoom(conversationId, opts = {}) {
|
|
1172
1210
|
const poolse = usePoolse();
|
|
1173
1211
|
const [status, setStatus] = useState("idle");
|
|
@@ -1217,7 +1255,12 @@ function useVoiceRoom(conversationId, opts = {}) {
|
|
|
1217
1255
|
if (!room) return;
|
|
1218
1256
|
setMuted(room.toggleMute());
|
|
1219
1257
|
}, [room]);
|
|
1220
|
-
|
|
1258
|
+
const alone = useAloneWatch({
|
|
1259
|
+
active: status === "connected",
|
|
1260
|
+
others: Math.max(0, participants.length - 1),
|
|
1261
|
+
graceMs: optsRef.current.aloneGraceMs ?? 1500
|
|
1262
|
+
});
|
|
1263
|
+
return { status, participants, muted, alone, error, join, leave, toggleMute };
|
|
1221
1264
|
}
|
|
1222
1265
|
function useCalls(userId, opts = {}) {
|
|
1223
1266
|
const ringTimeoutMs = opts.ringTimeoutMs ?? 45e3;
|