@poolse/react 2.27.0 → 2.29.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 +9 -0
- package/dist/index.cjs +50 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -185
- package/dist/index.d.ts +55 -185
- package/dist/index.js +50 -379
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule,
|
|
3
|
-
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, CallEndReason, CallLog, CallLogDisplay, CallLogEntry, CallLogMedia, CallMissedEntry, CallParticipantStatus, Conversation, ConversationCreateRequest, DeviceKind, LiveCall, LiveCallMember, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, ReadReceiptsState, RealtimeStatus, Uuid, callLogDisplayFor, describeCallLog, formatCallDuration, formatCallLogPreview, isCallLogMessage, isMessageVisibleTo, parseCallLog, parseCallLogBody } from '@poolse/sdk';
|
|
2
|
+
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule, LiveCall } from '@poolse/sdk';
|
|
3
|
+
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, CallEndReason, CallLog, CallLogDisplay, CallLogEntry, CallLogMedia, CallMissedEntry, CallParticipantStatus, Conversation, ConversationCreateRequest, DeviceKind, LiveCall, LiveCallMember, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, ReadReceiptsState, RealtimeStatus, RoomSession, Uuid, callLogDisplayFor, describeCallLog, formatCallDuration, formatCallLogPreview, isCallLogMessage, isMessageVisibleTo, parseCallLog, parseCallLogBody } from '@poolse/sdk';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
interface PoolseProviderProps {
|
|
@@ -549,11 +549,11 @@ interface UseCallRoom {
|
|
|
549
549
|
* Turns true only after somebody else has actually been on the call,
|
|
550
550
|
* so the caller waiting for an answer never trips it. Wire it to your
|
|
551
551
|
* hang-up path — a peer whose app was killed or whose phone lost
|
|
552
|
-
* signal
|
|
552
|
+
* signal never hangs up, and without this the survivor is
|
|
553
553
|
* left on a call screen that will never close on its own.
|
|
554
554
|
*
|
|
555
555
|
* useEffect(() => {
|
|
556
|
-
* if (media.alone)
|
|
556
|
+
* if (media.alone) room.leave();
|
|
557
557
|
* }, [media.alone]);
|
|
558
558
|
*/
|
|
559
559
|
alone: boolean;
|
|
@@ -562,8 +562,7 @@ interface UseCallRoom {
|
|
|
562
562
|
* Whether this deployment has an SFU.
|
|
563
563
|
*
|
|
564
564
|
* `null` until a join has been attempted, then `false` if the API
|
|
565
|
-
* answered 503
|
|
566
|
-
* to `useVoiceRoom`, which is how every call worked before the SFU.
|
|
565
|
+
* answered 503: this deployment carries no call media.
|
|
567
566
|
*/
|
|
568
567
|
sfuAvailable: boolean | null;
|
|
569
568
|
/** Connect. Resolves `false` when there is no SFU. */
|
|
@@ -579,193 +578,19 @@ interface UseCallRoom {
|
|
|
579
578
|
/**
|
|
580
579
|
* A call's media, carried by the SFU.
|
|
581
580
|
*
|
|
582
|
-
* Media only
|
|
583
|
-
*
|
|
584
|
-
*
|
|
581
|
+
* Media only — who is in the room and whether it is live come from
|
|
582
|
+
* `useRoom` / `useLiveCall`; this is what people sound and look like.
|
|
583
|
+
* `useRoom` wraps it.
|
|
585
584
|
*
|
|
586
585
|
* const media = useCallRoom(conversationId, { livekit, video: true });
|
|
587
586
|
* await media.join();
|
|
588
587
|
* await media.toggleCamera();
|
|
589
588
|
*
|
|
590
589
|
* Both the camera and the microphone can be turned on and off at any
|
|
591
|
-
* point during the call
|
|
592
|
-
* live connection is exactly what the peer-to-peer mesh cannot do.
|
|
590
|
+
* point during the call.
|
|
593
591
|
*/
|
|
594
592
|
declare function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom;
|
|
595
593
|
|
|
596
|
-
interface UseVoiceRoom {
|
|
597
|
-
status: VoiceStatus;
|
|
598
|
-
/** Everyone currently in the room, oldest join first. */
|
|
599
|
-
participants: VoiceParticipant[];
|
|
600
|
-
muted: boolean;
|
|
601
|
-
/**
|
|
602
|
-
* Everyone else has left and is not coming back.
|
|
603
|
-
*
|
|
604
|
-
* The mesh equivalent of `useCallRoom`'s flag of the same name — see
|
|
605
|
-
* there for why a call needs this on top of the explicit hang-up
|
|
606
|
-
* signal. Only meaningful for a room being used to carry a call; a
|
|
607
|
-
* Discord-style room you sit in alone is a normal state, so wire this
|
|
608
|
-
* to hang-up only on the call surface.
|
|
609
|
-
*/
|
|
610
|
-
alone: boolean;
|
|
611
|
-
error: Error | null;
|
|
612
|
-
/** Acquire the mic and connect. Safe to call twice. */
|
|
613
|
-
join: () => Promise<void>;
|
|
614
|
-
leave: () => void;
|
|
615
|
-
toggleMute: () => void;
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Discord-style voice room for a conversation: join, see who else is
|
|
619
|
-
* in, watch who's talking, mute yourself.
|
|
620
|
-
*
|
|
621
|
-
* The room is torn down when the conversation changes or the component
|
|
622
|
-
* unmounts, so a navigation away hangs up rather than leaving a phantom
|
|
623
|
-
* participant behind.
|
|
624
|
-
*
|
|
625
|
-
* const voice = useVoiceRoom(conversationId);
|
|
626
|
-
* <Button onPress={voice.join} title="Join Voice" />
|
|
627
|
-
*
|
|
628
|
-
* For ringing someone who hasn't joined yet, see `useCalls`.
|
|
629
|
-
*/
|
|
630
|
-
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions & {
|
|
631
|
-
/** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */
|
|
632
|
-
aloneGraceMs?: number;
|
|
633
|
-
}): UseVoiceRoom;
|
|
634
|
-
|
|
635
|
-
/** Where a call is in its lifecycle, from this device's point of view. */
|
|
636
|
-
type CallPhase = 'idle'
|
|
637
|
-
/** We placed a call and are waiting for an answer. */
|
|
638
|
-
| 'ringing-out'
|
|
639
|
-
/** Someone is ringing us. */
|
|
640
|
-
| 'ringing-in'
|
|
641
|
-
/** Both sides agreed; the voice room should be joined now. */
|
|
642
|
-
| 'active'
|
|
643
|
-
/** The far side said no. */
|
|
644
|
-
| 'declined'
|
|
645
|
-
/** The person we called is already on another call. */
|
|
646
|
-
| 'busy'
|
|
647
|
-
/** Nobody picked up before the ring timeout elapsed. */
|
|
648
|
-
| 'timed-out';
|
|
649
|
-
interface UseCallsOptions {
|
|
650
|
-
/**
|
|
651
|
-
* How long a ring may go unanswered, in milliseconds, before it is
|
|
652
|
-
* given up on. Defaults to 45s, roughly what the mainstream call apps
|
|
653
|
-
* use. Pass `0` to ring indefinitely.
|
|
654
|
-
*
|
|
655
|
-
* The server deliberately holds no timer — only the UI knows when it
|
|
656
|
-
* stopped waiting — so this is what actually ends an unanswered call.
|
|
657
|
-
* Both directions are covered: an outbound ring cancels itself, and an
|
|
658
|
-
* inbound one gives up too, otherwise a caller that crashed mid-ring
|
|
659
|
-
* would leave the callee's phone ringing forever.
|
|
660
|
-
*/
|
|
661
|
-
ringTimeoutMs?: number;
|
|
662
|
-
}
|
|
663
|
-
interface UseCalls {
|
|
664
|
-
phase: CallPhase;
|
|
665
|
-
/** Set while `phase` is `ringing-in`. */
|
|
666
|
-
incoming: IncomingCall | null;
|
|
667
|
-
/** Set while `phase` is `ringing-out` or `active`. */
|
|
668
|
-
outgoing: OutgoingCall | null;
|
|
669
|
-
/**
|
|
670
|
-
* Conversation whose voice room should be joined once `phase` turns
|
|
671
|
-
* `active` — the same id for both caller and callee.
|
|
672
|
-
*/
|
|
673
|
-
activeConversationId: string | null;
|
|
674
|
-
/**
|
|
675
|
-
* What the current call opened as.
|
|
676
|
-
*
|
|
677
|
-
* `'audio'` when nothing is in flight. Either side can still turn
|
|
678
|
-
* their camera on mid-call — this is what was rung, which is what the
|
|
679
|
-
* incoming UI has to commit to before the user answers.
|
|
680
|
-
*/
|
|
681
|
-
media: CallMedia;
|
|
682
|
-
error: Error | null;
|
|
683
|
-
/** Ring every other member of a conversation. */
|
|
684
|
-
call: (conversationId: string, media?: CallMedia) => Promise<void>;
|
|
685
|
-
/**
|
|
686
|
-
* Register a ring that arrived by some route other than the socket —
|
|
687
|
-
* in practice a VoIP push.
|
|
688
|
-
*
|
|
689
|
-
* Without this the push path shows a ring the state machine knows
|
|
690
|
-
* nothing about, and every signal that ends a call is guarded on
|
|
691
|
-
* state the machine never had: the caller hanging up sent
|
|
692
|
-
* `call:cancelled`, the guard found no matching `incoming`, and the
|
|
693
|
-
* callee's phone rang on until its own timeout.
|
|
694
|
-
*
|
|
695
|
-
* Idempotent per call id, because the socket almost always delivers
|
|
696
|
-
* the same call a moment later — that is one ring arriving twice, not
|
|
697
|
-
* a second caller.
|
|
698
|
-
*/
|
|
699
|
-
ring: (call: IncomingCall) => void;
|
|
700
|
-
/**
|
|
701
|
-
* A call was torn down from outside this state machine.
|
|
702
|
-
*
|
|
703
|
-
* The counterpart to {@link ring}: the caller withdrew, or the call
|
|
704
|
-
* ended, and the news reached this device as a VoIP push rather than
|
|
705
|
-
* over the socket — which is the normal case for a phone that was
|
|
706
|
-
* asleep when the ring arrived and whose socket may not be up yet.
|
|
707
|
-
*
|
|
708
|
-
* Ignores call ids this client is not in, so a teardown for a
|
|
709
|
-
* previous call cannot end the current one.
|
|
710
|
-
*/
|
|
711
|
-
dropped: (callId: string) => void;
|
|
712
|
-
/**
|
|
713
|
-
* Answer the inbound ring.
|
|
714
|
-
*
|
|
715
|
-
* Pass the call explicitly when it didn't arrive over the socket — a
|
|
716
|
-
* VoIP push can launch the app cold, in which case this hook has no
|
|
717
|
-
* `incoming` state and the push payload is the only source of truth.
|
|
718
|
-
*/
|
|
719
|
-
accept: (call?: IncomingCall) => Promise<void>;
|
|
720
|
-
/** Reject the inbound ring. Takes an explicit call for the same
|
|
721
|
-
* cold-launch reason as {@link accept}. */
|
|
722
|
-
decline: (call?: IncomingCall) => Promise<void>;
|
|
723
|
-
/** Hang up an outbound ring before it's answered. */
|
|
724
|
-
cancel: () => Promise<void>;
|
|
725
|
-
/**
|
|
726
|
-
* End the call, whatever state it is in.
|
|
727
|
-
*
|
|
728
|
-
* The one action a UI's hang-up button should call: it sends the right
|
|
729
|
-
* signal for the current phase — cancel while ringing out, decline
|
|
730
|
-
* while ringing in, hangup once connected — and always returns to
|
|
731
|
-
* idle, even if the signal fails. `reset` alone clears local state
|
|
732
|
-
* only, which leaves the other side in the call.
|
|
733
|
-
*/
|
|
734
|
-
hangUp: () => Promise<void>;
|
|
735
|
-
/** Drop back to idle — call after leaving the room, or to clear a
|
|
736
|
-
* `declined` / `busy` / `timed-out` state the UI has finished
|
|
737
|
-
* showing. */
|
|
738
|
-
reset: () => void;
|
|
739
|
-
/**
|
|
740
|
-
* Tell the hook how many OTHER people are currently on the call's
|
|
741
|
-
* media. `hangUp` consults it: with two or more others connected,
|
|
742
|
-
* hanging up just leaves — the call continues without you — and the
|
|
743
|
-
* end-the-call signal is only sent when at most one other remains.
|
|
744
|
-
* Every hang-up path funnels through the hook (the in-call button,
|
|
745
|
-
* CallKit's end event, the OS back gesture), so this is the ONE
|
|
746
|
-
* place group calls are protected from being ended by a leaver.
|
|
747
|
-
*/
|
|
748
|
-
reportOthersOnCall: (count: number) => void;
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* WhatsApp-style calling: ring a conversation, show an incoming-call
|
|
752
|
-
* screen, accept or decline.
|
|
753
|
-
*
|
|
754
|
-
* This hook is only the *invitation* half. Audio starts when you join
|
|
755
|
-
* the voice room, which the host app does once `phase` is `active`:
|
|
756
|
-
*
|
|
757
|
-
* const calls = useCalls(myUserId);
|
|
758
|
-
* const voice = useVoiceRoom(calls.activeConversationId);
|
|
759
|
-
*
|
|
760
|
-
* useEffect(() => {
|
|
761
|
-
* if (calls.phase === 'active') void voice.join();
|
|
762
|
-
* }, [calls.phase]);
|
|
763
|
-
*
|
|
764
|
-
* Keeping them separate means a "join voice" button and a ringing call
|
|
765
|
-
* share exactly one implementation of the media path.
|
|
766
|
-
*/
|
|
767
|
-
declare function useCalls(userId: string | null, opts?: UseCallsOptions): UseCalls;
|
|
768
|
-
|
|
769
594
|
interface UseLiveCall {
|
|
770
595
|
/** The call running on the conversation right now, or null. */
|
|
771
596
|
call: LiveCall | null;
|
|
@@ -783,6 +608,51 @@ interface UseLiveCall {
|
|
|
783
608
|
*/
|
|
784
609
|
declare function useLiveCall(conversationId: string | null): UseLiveCall;
|
|
785
610
|
|
|
611
|
+
interface UseRoomOptions {
|
|
612
|
+
/** `livekit-client`, imported by your app: `import * as livekit from 'livekit-client'`. */
|
|
613
|
+
livekit: LiveKitModule;
|
|
614
|
+
}
|
|
615
|
+
interface UseRoom {
|
|
616
|
+
/**
|
|
617
|
+
* The room (or call) running on the conversation right now, whether
|
|
618
|
+
* or not this user is in it — what a "Join" button reads.
|
|
619
|
+
*/
|
|
620
|
+
live: ReturnType<typeof useLiveCall>['call'];
|
|
621
|
+
/** User ids in the room at this moment. */
|
|
622
|
+
presentIds: string[];
|
|
623
|
+
/** This user is in (or connecting to) the room. */
|
|
624
|
+
joined: boolean;
|
|
625
|
+
/** Starting or joining is in flight. */
|
|
626
|
+
joining: boolean;
|
|
627
|
+
/**
|
|
628
|
+
* Drop in: starts the conversation's room if none is live, or joins
|
|
629
|
+
* the one that is (a ringing call included). Nobody's phone rings.
|
|
630
|
+
* `video` turns the camera on as you arrive. `{ ring: true }` rings
|
|
631
|
+
* the other members' phones as well — an opt-in for apps where web
|
|
632
|
+
* calls people (a support desk); rooms never ring otherwise.
|
|
633
|
+
*/
|
|
634
|
+
join: (media?: 'audio' | 'video', opts?: {
|
|
635
|
+
ring?: boolean;
|
|
636
|
+
}) => Promise<void>;
|
|
637
|
+
/** Leave. The room carries on for whoever is still in it. */
|
|
638
|
+
leave: () => void;
|
|
639
|
+
/** The media side: participants, mic/camera, devices (see `useCallRoom`). */
|
|
640
|
+
media: UseCallRoom;
|
|
641
|
+
error: Error | null;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* A conversation's room — Meet-style: anyone in the conversation drops
|
|
645
|
+
* in for voice or video while the chat carries on, and nothing rings.
|
|
646
|
+
*
|
|
647
|
+
* const room = useRoom(conversationId, { livekit });
|
|
648
|
+
* room.live ? <button onClick={() => room.join()}>Join</button>
|
|
649
|
+
* : <button onClick={() => room.join('video')}>Start a video room</button>;
|
|
650
|
+
*
|
|
651
|
+
* The room ends on its own once it has been empty for a short while,
|
|
652
|
+
* and leaves one line in the conversation's history.
|
|
653
|
+
*/
|
|
654
|
+
declare function useRoom(conversationId: string | null, opts: UseRoomOptions): UseRoom;
|
|
655
|
+
|
|
786
656
|
interface UseReadReceipts {
|
|
787
657
|
/**
|
|
788
658
|
* Whether this user sees other people's read state. False → show no
|
|
@@ -822,4 +692,4 @@ declare function canEditOwnMessage(args: {
|
|
|
822
692
|
now?: number;
|
|
823
693
|
}): boolean;
|
|
824
694
|
|
|
825
|
-
export {
|
|
695
|
+
export { EDIT_WINDOW_MS, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCallRoom, type UseCallRoomOptions, type UseLiveCall, type UseReadReceipts, type UseRoom, type UseRoomOptions, type UseUserState, canEditOwnMessage, computeGroupPosition, formatDayLabel, receiptsOf, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCallRoom, useConversation, useConversations, useLiveCall, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useReadReceipts, useRealtimeStatus, useRoom, useThread, useTyping, useUser };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule,
|
|
3
|
-
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, CallEndReason, CallLog, CallLogDisplay, CallLogEntry, CallLogMedia, CallMissedEntry, CallParticipantStatus, Conversation, ConversationCreateRequest, DeviceKind, LiveCall, LiveCallMember, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, ReadReceiptsState, RealtimeStatus, Uuid, callLogDisplayFor, describeCallLog, formatCallDuration, formatCallLogPreview, isCallLogMessage, isMessageVisibleTo, parseCallLog, parseCallLogBody } from '@poolse/sdk';
|
|
2
|
+
import { PoolseConfig, Poolse, Me, Uuid, Conversation, ConversationCreateRequest, Membership, MemberRole, Message, MessageCreateRequest, RealtimeStatus, Attachment, AttachmentUploadInput, PoolseUserProfile, CallRoomStatus, CallParticipant, CameraFacing, CallDeviceKind, CallDevice, LiveKitModule, LiveCall } from '@poolse/sdk';
|
|
3
|
+
export { ApiError, Attachment, AttachmentStatus, AttachmentUploadInput, AttachmentUploadRequest, AttachmentUploadResponse, AuthError, CallEndReason, CallLog, CallLogDisplay, CallLogEntry, CallLogMedia, CallMissedEntry, CallParticipantStatus, Conversation, ConversationCreateRequest, DeviceKind, LiveCall, LiveCallMember, Me, MemberRole, Membership, Message, MessageCreateRequest, MessageType, NetworkError, PoolseConfig, PoolseError, PoolseUserProfile, RateLimitedError, ReadReceiptsState, RealtimeStatus, RoomSession, Uuid, callLogDisplayFor, describeCallLog, formatCallDuration, formatCallLogPreview, isCallLogMessage, isMessageVisibleTo, parseCallLog, parseCallLogBody } from '@poolse/sdk';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
interface PoolseProviderProps {
|
|
@@ -549,11 +549,11 @@ interface UseCallRoom {
|
|
|
549
549
|
* Turns true only after somebody else has actually been on the call,
|
|
550
550
|
* so the caller waiting for an answer never trips it. Wire it to your
|
|
551
551
|
* hang-up path — a peer whose app was killed or whose phone lost
|
|
552
|
-
* signal
|
|
552
|
+
* signal never hangs up, and without this the survivor is
|
|
553
553
|
* left on a call screen that will never close on its own.
|
|
554
554
|
*
|
|
555
555
|
* useEffect(() => {
|
|
556
|
-
* if (media.alone)
|
|
556
|
+
* if (media.alone) room.leave();
|
|
557
557
|
* }, [media.alone]);
|
|
558
558
|
*/
|
|
559
559
|
alone: boolean;
|
|
@@ -562,8 +562,7 @@ interface UseCallRoom {
|
|
|
562
562
|
* Whether this deployment has an SFU.
|
|
563
563
|
*
|
|
564
564
|
* `null` until a join has been attempted, then `false` if the API
|
|
565
|
-
* answered 503
|
|
566
|
-
* to `useVoiceRoom`, which is how every call worked before the SFU.
|
|
565
|
+
* answered 503: this deployment carries no call media.
|
|
567
566
|
*/
|
|
568
567
|
sfuAvailable: boolean | null;
|
|
569
568
|
/** Connect. Resolves `false` when there is no SFU. */
|
|
@@ -579,193 +578,19 @@ interface UseCallRoom {
|
|
|
579
578
|
/**
|
|
580
579
|
* A call's media, carried by the SFU.
|
|
581
580
|
*
|
|
582
|
-
* Media only
|
|
583
|
-
*
|
|
584
|
-
*
|
|
581
|
+
* Media only — who is in the room and whether it is live come from
|
|
582
|
+
* `useRoom` / `useLiveCall`; this is what people sound and look like.
|
|
583
|
+
* `useRoom` wraps it.
|
|
585
584
|
*
|
|
586
585
|
* const media = useCallRoom(conversationId, { livekit, video: true });
|
|
587
586
|
* await media.join();
|
|
588
587
|
* await media.toggleCamera();
|
|
589
588
|
*
|
|
590
589
|
* Both the camera and the microphone can be turned on and off at any
|
|
591
|
-
* point during the call
|
|
592
|
-
* live connection is exactly what the peer-to-peer mesh cannot do.
|
|
590
|
+
* point during the call.
|
|
593
591
|
*/
|
|
594
592
|
declare function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom;
|
|
595
593
|
|
|
596
|
-
interface UseVoiceRoom {
|
|
597
|
-
status: VoiceStatus;
|
|
598
|
-
/** Everyone currently in the room, oldest join first. */
|
|
599
|
-
participants: VoiceParticipant[];
|
|
600
|
-
muted: boolean;
|
|
601
|
-
/**
|
|
602
|
-
* Everyone else has left and is not coming back.
|
|
603
|
-
*
|
|
604
|
-
* The mesh equivalent of `useCallRoom`'s flag of the same name — see
|
|
605
|
-
* there for why a call needs this on top of the explicit hang-up
|
|
606
|
-
* signal. Only meaningful for a room being used to carry a call; a
|
|
607
|
-
* Discord-style room you sit in alone is a normal state, so wire this
|
|
608
|
-
* to hang-up only on the call surface.
|
|
609
|
-
*/
|
|
610
|
-
alone: boolean;
|
|
611
|
-
error: Error | null;
|
|
612
|
-
/** Acquire the mic and connect. Safe to call twice. */
|
|
613
|
-
join: () => Promise<void>;
|
|
614
|
-
leave: () => void;
|
|
615
|
-
toggleMute: () => void;
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Discord-style voice room for a conversation: join, see who else is
|
|
619
|
-
* in, watch who's talking, mute yourself.
|
|
620
|
-
*
|
|
621
|
-
* The room is torn down when the conversation changes or the component
|
|
622
|
-
* unmounts, so a navigation away hangs up rather than leaving a phantom
|
|
623
|
-
* participant behind.
|
|
624
|
-
*
|
|
625
|
-
* const voice = useVoiceRoom(conversationId);
|
|
626
|
-
* <Button onPress={voice.join} title="Join Voice" />
|
|
627
|
-
*
|
|
628
|
-
* For ringing someone who hasn't joined yet, see `useCalls`.
|
|
629
|
-
*/
|
|
630
|
-
declare function useVoiceRoom(conversationId: string | null, opts?: VoiceRoomOptions & {
|
|
631
|
-
/** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */
|
|
632
|
-
aloneGraceMs?: number;
|
|
633
|
-
}): UseVoiceRoom;
|
|
634
|
-
|
|
635
|
-
/** Where a call is in its lifecycle, from this device's point of view. */
|
|
636
|
-
type CallPhase = 'idle'
|
|
637
|
-
/** We placed a call and are waiting for an answer. */
|
|
638
|
-
| 'ringing-out'
|
|
639
|
-
/** Someone is ringing us. */
|
|
640
|
-
| 'ringing-in'
|
|
641
|
-
/** Both sides agreed; the voice room should be joined now. */
|
|
642
|
-
| 'active'
|
|
643
|
-
/** The far side said no. */
|
|
644
|
-
| 'declined'
|
|
645
|
-
/** The person we called is already on another call. */
|
|
646
|
-
| 'busy'
|
|
647
|
-
/** Nobody picked up before the ring timeout elapsed. */
|
|
648
|
-
| 'timed-out';
|
|
649
|
-
interface UseCallsOptions {
|
|
650
|
-
/**
|
|
651
|
-
* How long a ring may go unanswered, in milliseconds, before it is
|
|
652
|
-
* given up on. Defaults to 45s, roughly what the mainstream call apps
|
|
653
|
-
* use. Pass `0` to ring indefinitely.
|
|
654
|
-
*
|
|
655
|
-
* The server deliberately holds no timer — only the UI knows when it
|
|
656
|
-
* stopped waiting — so this is what actually ends an unanswered call.
|
|
657
|
-
* Both directions are covered: an outbound ring cancels itself, and an
|
|
658
|
-
* inbound one gives up too, otherwise a caller that crashed mid-ring
|
|
659
|
-
* would leave the callee's phone ringing forever.
|
|
660
|
-
*/
|
|
661
|
-
ringTimeoutMs?: number;
|
|
662
|
-
}
|
|
663
|
-
interface UseCalls {
|
|
664
|
-
phase: CallPhase;
|
|
665
|
-
/** Set while `phase` is `ringing-in`. */
|
|
666
|
-
incoming: IncomingCall | null;
|
|
667
|
-
/** Set while `phase` is `ringing-out` or `active`. */
|
|
668
|
-
outgoing: OutgoingCall | null;
|
|
669
|
-
/**
|
|
670
|
-
* Conversation whose voice room should be joined once `phase` turns
|
|
671
|
-
* `active` — the same id for both caller and callee.
|
|
672
|
-
*/
|
|
673
|
-
activeConversationId: string | null;
|
|
674
|
-
/**
|
|
675
|
-
* What the current call opened as.
|
|
676
|
-
*
|
|
677
|
-
* `'audio'` when nothing is in flight. Either side can still turn
|
|
678
|
-
* their camera on mid-call — this is what was rung, which is what the
|
|
679
|
-
* incoming UI has to commit to before the user answers.
|
|
680
|
-
*/
|
|
681
|
-
media: CallMedia;
|
|
682
|
-
error: Error | null;
|
|
683
|
-
/** Ring every other member of a conversation. */
|
|
684
|
-
call: (conversationId: string, media?: CallMedia) => Promise<void>;
|
|
685
|
-
/**
|
|
686
|
-
* Register a ring that arrived by some route other than the socket —
|
|
687
|
-
* in practice a VoIP push.
|
|
688
|
-
*
|
|
689
|
-
* Without this the push path shows a ring the state machine knows
|
|
690
|
-
* nothing about, and every signal that ends a call is guarded on
|
|
691
|
-
* state the machine never had: the caller hanging up sent
|
|
692
|
-
* `call:cancelled`, the guard found no matching `incoming`, and the
|
|
693
|
-
* callee's phone rang on until its own timeout.
|
|
694
|
-
*
|
|
695
|
-
* Idempotent per call id, because the socket almost always delivers
|
|
696
|
-
* the same call a moment later — that is one ring arriving twice, not
|
|
697
|
-
* a second caller.
|
|
698
|
-
*/
|
|
699
|
-
ring: (call: IncomingCall) => void;
|
|
700
|
-
/**
|
|
701
|
-
* A call was torn down from outside this state machine.
|
|
702
|
-
*
|
|
703
|
-
* The counterpart to {@link ring}: the caller withdrew, or the call
|
|
704
|
-
* ended, and the news reached this device as a VoIP push rather than
|
|
705
|
-
* over the socket — which is the normal case for a phone that was
|
|
706
|
-
* asleep when the ring arrived and whose socket may not be up yet.
|
|
707
|
-
*
|
|
708
|
-
* Ignores call ids this client is not in, so a teardown for a
|
|
709
|
-
* previous call cannot end the current one.
|
|
710
|
-
*/
|
|
711
|
-
dropped: (callId: string) => void;
|
|
712
|
-
/**
|
|
713
|
-
* Answer the inbound ring.
|
|
714
|
-
*
|
|
715
|
-
* Pass the call explicitly when it didn't arrive over the socket — a
|
|
716
|
-
* VoIP push can launch the app cold, in which case this hook has no
|
|
717
|
-
* `incoming` state and the push payload is the only source of truth.
|
|
718
|
-
*/
|
|
719
|
-
accept: (call?: IncomingCall) => Promise<void>;
|
|
720
|
-
/** Reject the inbound ring. Takes an explicit call for the same
|
|
721
|
-
* cold-launch reason as {@link accept}. */
|
|
722
|
-
decline: (call?: IncomingCall) => Promise<void>;
|
|
723
|
-
/** Hang up an outbound ring before it's answered. */
|
|
724
|
-
cancel: () => Promise<void>;
|
|
725
|
-
/**
|
|
726
|
-
* End the call, whatever state it is in.
|
|
727
|
-
*
|
|
728
|
-
* The one action a UI's hang-up button should call: it sends the right
|
|
729
|
-
* signal for the current phase — cancel while ringing out, decline
|
|
730
|
-
* while ringing in, hangup once connected — and always returns to
|
|
731
|
-
* idle, even if the signal fails. `reset` alone clears local state
|
|
732
|
-
* only, which leaves the other side in the call.
|
|
733
|
-
*/
|
|
734
|
-
hangUp: () => Promise<void>;
|
|
735
|
-
/** Drop back to idle — call after leaving the room, or to clear a
|
|
736
|
-
* `declined` / `busy` / `timed-out` state the UI has finished
|
|
737
|
-
* showing. */
|
|
738
|
-
reset: () => void;
|
|
739
|
-
/**
|
|
740
|
-
* Tell the hook how many OTHER people are currently on the call's
|
|
741
|
-
* media. `hangUp` consults it: with two or more others connected,
|
|
742
|
-
* hanging up just leaves — the call continues without you — and the
|
|
743
|
-
* end-the-call signal is only sent when at most one other remains.
|
|
744
|
-
* Every hang-up path funnels through the hook (the in-call button,
|
|
745
|
-
* CallKit's end event, the OS back gesture), so this is the ONE
|
|
746
|
-
* place group calls are protected from being ended by a leaver.
|
|
747
|
-
*/
|
|
748
|
-
reportOthersOnCall: (count: number) => void;
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* WhatsApp-style calling: ring a conversation, show an incoming-call
|
|
752
|
-
* screen, accept or decline.
|
|
753
|
-
*
|
|
754
|
-
* This hook is only the *invitation* half. Audio starts when you join
|
|
755
|
-
* the voice room, which the host app does once `phase` is `active`:
|
|
756
|
-
*
|
|
757
|
-
* const calls = useCalls(myUserId);
|
|
758
|
-
* const voice = useVoiceRoom(calls.activeConversationId);
|
|
759
|
-
*
|
|
760
|
-
* useEffect(() => {
|
|
761
|
-
* if (calls.phase === 'active') void voice.join();
|
|
762
|
-
* }, [calls.phase]);
|
|
763
|
-
*
|
|
764
|
-
* Keeping them separate means a "join voice" button and a ringing call
|
|
765
|
-
* share exactly one implementation of the media path.
|
|
766
|
-
*/
|
|
767
|
-
declare function useCalls(userId: string | null, opts?: UseCallsOptions): UseCalls;
|
|
768
|
-
|
|
769
594
|
interface UseLiveCall {
|
|
770
595
|
/** The call running on the conversation right now, or null. */
|
|
771
596
|
call: LiveCall | null;
|
|
@@ -783,6 +608,51 @@ interface UseLiveCall {
|
|
|
783
608
|
*/
|
|
784
609
|
declare function useLiveCall(conversationId: string | null): UseLiveCall;
|
|
785
610
|
|
|
611
|
+
interface UseRoomOptions {
|
|
612
|
+
/** `livekit-client`, imported by your app: `import * as livekit from 'livekit-client'`. */
|
|
613
|
+
livekit: LiveKitModule;
|
|
614
|
+
}
|
|
615
|
+
interface UseRoom {
|
|
616
|
+
/**
|
|
617
|
+
* The room (or call) running on the conversation right now, whether
|
|
618
|
+
* or not this user is in it — what a "Join" button reads.
|
|
619
|
+
*/
|
|
620
|
+
live: ReturnType<typeof useLiveCall>['call'];
|
|
621
|
+
/** User ids in the room at this moment. */
|
|
622
|
+
presentIds: string[];
|
|
623
|
+
/** This user is in (or connecting to) the room. */
|
|
624
|
+
joined: boolean;
|
|
625
|
+
/** Starting or joining is in flight. */
|
|
626
|
+
joining: boolean;
|
|
627
|
+
/**
|
|
628
|
+
* Drop in: starts the conversation's room if none is live, or joins
|
|
629
|
+
* the one that is (a ringing call included). Nobody's phone rings.
|
|
630
|
+
* `video` turns the camera on as you arrive. `{ ring: true }` rings
|
|
631
|
+
* the other members' phones as well — an opt-in for apps where web
|
|
632
|
+
* calls people (a support desk); rooms never ring otherwise.
|
|
633
|
+
*/
|
|
634
|
+
join: (media?: 'audio' | 'video', opts?: {
|
|
635
|
+
ring?: boolean;
|
|
636
|
+
}) => Promise<void>;
|
|
637
|
+
/** Leave. The room carries on for whoever is still in it. */
|
|
638
|
+
leave: () => void;
|
|
639
|
+
/** The media side: participants, mic/camera, devices (see `useCallRoom`). */
|
|
640
|
+
media: UseCallRoom;
|
|
641
|
+
error: Error | null;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* A conversation's room — Meet-style: anyone in the conversation drops
|
|
645
|
+
* in for voice or video while the chat carries on, and nothing rings.
|
|
646
|
+
*
|
|
647
|
+
* const room = useRoom(conversationId, { livekit });
|
|
648
|
+
* room.live ? <button onClick={() => room.join()}>Join</button>
|
|
649
|
+
* : <button onClick={() => room.join('video')}>Start a video room</button>;
|
|
650
|
+
*
|
|
651
|
+
* The room ends on its own once it has been empty for a short while,
|
|
652
|
+
* and leaves one line in the conversation's history.
|
|
653
|
+
*/
|
|
654
|
+
declare function useRoom(conversationId: string | null, opts: UseRoomOptions): UseRoom;
|
|
655
|
+
|
|
786
656
|
interface UseReadReceipts {
|
|
787
657
|
/**
|
|
788
658
|
* Whether this user sees other people's read state. False → show no
|
|
@@ -822,4 +692,4 @@ declare function canEditOwnMessage(args: {
|
|
|
822
692
|
now?: number;
|
|
823
693
|
}): boolean;
|
|
824
694
|
|
|
825
|
-
export {
|
|
695
|
+
export { EDIT_WINDOW_MS, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCallRoom, type UseCallRoomOptions, type UseLiveCall, type UseReadReceipts, type UseRoom, type UseRoomOptions, type UseUserState, canEditOwnMessage, computeGroupPosition, formatDayLabel, receiptsOf, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCallRoom, useConversation, useConversations, useLiveCall, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useReadReceipts, useRealtimeStatus, useRoom, useThread, useTyping, useUser };
|