@poolse/react 2.9.0 → 2.10.1

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.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, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall } from '@poolse/sdk';
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';
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
 
@@ -485,6 +485,63 @@ declare function sameDay(a: string, b: string): boolean;
485
485
  */
486
486
  declare function formatDayLabel(iso: string, now?: Date): string;
487
487
 
488
+ interface UseCallRoomOptions {
489
+ /**
490
+ * `livekit-client`, imported by your app:
491
+ *
492
+ * import * as livekit from 'livekit-client';
493
+ *
494
+ * Passed in rather than imported by the SDK because Metro bundles from
495
+ * the static import graph and cannot follow the `require` that tsup
496
+ * emits — a dependency the SDK imports for itself never reaches a
497
+ * React Native bundle.
498
+ */
499
+ livekit: LiveKitModule;
500
+ /** Publish the camera on join. An audio call starts with it off. */
501
+ video?: boolean;
502
+ /** Join muted. */
503
+ muted?: boolean;
504
+ }
505
+ interface UseCallRoom {
506
+ status: CallRoomStatus;
507
+ /** Everyone on the call, the local participant first. */
508
+ participants: CallParticipant[];
509
+ cameraEnabled: boolean;
510
+ micEnabled: boolean;
511
+ error: Error | null;
512
+ /**
513
+ * Whether this deployment has an SFU.
514
+ *
515
+ * `null` until a join has been attempted, then `false` if the API
516
+ * answered 503. A `false` here is not a failure — it means fall back
517
+ * to `useVoiceRoom`, which is how every call worked before the SFU.
518
+ */
519
+ sfuAvailable: boolean | null;
520
+ /** Connect. Resolves `false` when there is no SFU. */
521
+ join: () => Promise<boolean>;
522
+ leave: () => void;
523
+ setCameraEnabled: (enabled: boolean) => Promise<void>;
524
+ toggleCamera: () => Promise<void>;
525
+ setMicrophoneEnabled: (enabled: boolean) => Promise<void>;
526
+ toggleMic: () => Promise<void>;
527
+ }
528
+ /**
529
+ * A call's media, carried by the SFU.
530
+ *
531
+ * Media only. Ringing, accept/decline/hangup and the poolse roster stay
532
+ * with `useCalls` and `useVoiceRoom`; this is what people sound and look
533
+ * like. A call screen normally uses both.
534
+ *
535
+ * const media = useCallRoom(conversationId, { livekit, video: true });
536
+ * await media.join();
537
+ * await media.toggleCamera();
538
+ *
539
+ * Both the camera and the microphone can be turned on and off at any
540
+ * point during the call — that is the SFU's doing, since renegotiating a
541
+ * live connection is exactly what the peer-to-peer mesh cannot do.
542
+ */
543
+ declare function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom;
544
+
488
545
  interface UseVoiceRoom {
489
546
  status: VoiceStatus;
490
547
  /** Everyone currently in the room, oldest join first. */
@@ -550,9 +607,17 @@ interface UseCalls {
550
607
  * `active` — the same id for both caller and callee.
551
608
  */
552
609
  activeConversationId: string | null;
610
+ /**
611
+ * What the current call opened as.
612
+ *
613
+ * `'audio'` when nothing is in flight. Either side can still turn
614
+ * their camera on mid-call — this is what was rung, which is what the
615
+ * incoming UI has to commit to before the user answers.
616
+ */
617
+ media: CallMedia;
553
618
  error: Error | null;
554
619
  /** Ring every other member of a conversation. */
555
- call: (conversationId: string) => Promise<void>;
620
+ call: (conversationId: string, media?: CallMedia) => Promise<void>;
556
621
  /**
557
622
  * Answer the inbound ring.
558
623
  *
@@ -600,4 +665,4 @@ interface UseCalls {
600
665
  */
601
666
  declare function useCalls(userId: string | null, opts?: UseCallsOptions): UseCalls;
602
667
 
603
- export { type CallPhase, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCalls, type UseUserState, type UseVoiceRoom, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
668
+ export { type CallPhase, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCallRoom, type UseCallRoomOptions, type UseCalls, type UseUserState, type UseVoiceRoom, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCallRoom, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
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, VoiceStatus, VoiceParticipant, VoiceRoomOptions, IncomingCall, OutgoingCall } from '@poolse/sdk';
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';
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
 
@@ -485,6 +485,63 @@ declare function sameDay(a: string, b: string): boolean;
485
485
  */
486
486
  declare function formatDayLabel(iso: string, now?: Date): string;
487
487
 
488
+ interface UseCallRoomOptions {
489
+ /**
490
+ * `livekit-client`, imported by your app:
491
+ *
492
+ * import * as livekit from 'livekit-client';
493
+ *
494
+ * Passed in rather than imported by the SDK because Metro bundles from
495
+ * the static import graph and cannot follow the `require` that tsup
496
+ * emits — a dependency the SDK imports for itself never reaches a
497
+ * React Native bundle.
498
+ */
499
+ livekit: LiveKitModule;
500
+ /** Publish the camera on join. An audio call starts with it off. */
501
+ video?: boolean;
502
+ /** Join muted. */
503
+ muted?: boolean;
504
+ }
505
+ interface UseCallRoom {
506
+ status: CallRoomStatus;
507
+ /** Everyone on the call, the local participant first. */
508
+ participants: CallParticipant[];
509
+ cameraEnabled: boolean;
510
+ micEnabled: boolean;
511
+ error: Error | null;
512
+ /**
513
+ * Whether this deployment has an SFU.
514
+ *
515
+ * `null` until a join has been attempted, then `false` if the API
516
+ * answered 503. A `false` here is not a failure — it means fall back
517
+ * to `useVoiceRoom`, which is how every call worked before the SFU.
518
+ */
519
+ sfuAvailable: boolean | null;
520
+ /** Connect. Resolves `false` when there is no SFU. */
521
+ join: () => Promise<boolean>;
522
+ leave: () => void;
523
+ setCameraEnabled: (enabled: boolean) => Promise<void>;
524
+ toggleCamera: () => Promise<void>;
525
+ setMicrophoneEnabled: (enabled: boolean) => Promise<void>;
526
+ toggleMic: () => Promise<void>;
527
+ }
528
+ /**
529
+ * A call's media, carried by the SFU.
530
+ *
531
+ * Media only. Ringing, accept/decline/hangup and the poolse roster stay
532
+ * with `useCalls` and `useVoiceRoom`; this is what people sound and look
533
+ * like. A call screen normally uses both.
534
+ *
535
+ * const media = useCallRoom(conversationId, { livekit, video: true });
536
+ * await media.join();
537
+ * await media.toggleCamera();
538
+ *
539
+ * Both the camera and the microphone can be turned on and off at any
540
+ * point during the call — that is the SFU's doing, since renegotiating a
541
+ * live connection is exactly what the peer-to-peer mesh cannot do.
542
+ */
543
+ declare function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom;
544
+
488
545
  interface UseVoiceRoom {
489
546
  status: VoiceStatus;
490
547
  /** Everyone currently in the room, oldest join first. */
@@ -550,9 +607,17 @@ interface UseCalls {
550
607
  * `active` — the same id for both caller and callee.
551
608
  */
552
609
  activeConversationId: string | null;
610
+ /**
611
+ * What the current call opened as.
612
+ *
613
+ * `'audio'` when nothing is in flight. Either side can still turn
614
+ * their camera on mid-call — this is what was rung, which is what the
615
+ * incoming UI has to commit to before the user answers.
616
+ */
617
+ media: CallMedia;
553
618
  error: Error | null;
554
619
  /** Ring every other member of a conversation. */
555
- call: (conversationId: string) => Promise<void>;
620
+ call: (conversationId: string, media?: CallMedia) => Promise<void>;
556
621
  /**
557
622
  * Answer the inbound ring.
558
623
  *
@@ -600,4 +665,4 @@ interface UseCalls {
600
665
  */
601
666
  declare function useCalls(userId: string | null, opts?: UseCallsOptions): UseCalls;
602
667
 
603
- export { type CallPhase, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCalls, type UseUserState, type UseVoiceRoom, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
668
+ export { type CallPhase, type GroupPosition, PoolseProvider, type PoolseProviderProps, type ReactionMap, type UploadItem, type UploadItemStatus, type UseCallRoom, type UseCallRoomOptions, type UseCalls, type UseUserState, type UseVoiceRoom, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCallRoom, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
package/dist/index.js CHANGED
@@ -1062,6 +1062,112 @@ function formatDayLabel(iso, now = /* @__PURE__ */ new Date()) {
1062
1062
  }
1063
1063
  return d.toLocaleDateString(void 0, { day: "numeric", month: "short", year: "numeric" });
1064
1064
  }
1065
+ function useCallRoom(conversationId, opts) {
1066
+ const poolse = usePoolse();
1067
+ const [status, setStatus] = useState("idle");
1068
+ const [participants, setParticipants] = useState([]);
1069
+ const [cameraEnabled, setCamera] = useState(false);
1070
+ const [micEnabled, setMic] = useState(false);
1071
+ const [error, setError] = useState(null);
1072
+ const [sfuAvailable, setSfuAvailable] = useState(null);
1073
+ const optsRef = useRef(opts);
1074
+ const joined = useRef(false);
1075
+ const room = useMemo(() => {
1076
+ if (!conversationId) return null;
1077
+ return poolse.call(conversationId, {
1078
+ livekit: optsRef.current.livekit,
1079
+ ...optsRef.current.video !== void 0 ? { video: optsRef.current.video } : {},
1080
+ ...optsRef.current.muted !== void 0 ? { muted: optsRef.current.muted } : {}
1081
+ });
1082
+ }, [poolse, conversationId]);
1083
+ const sync = useCallback((target) => {
1084
+ if (!target) return;
1085
+ setCamera(target.isCameraEnabled());
1086
+ setMic(target.isMicrophoneEnabled());
1087
+ }, []);
1088
+ useEffect(() => {
1089
+ if (!room) {
1090
+ setStatus("idle");
1091
+ setParticipants([]);
1092
+ return;
1093
+ }
1094
+ setStatus(room.getStatus());
1095
+ setParticipants(room.getParticipants());
1096
+ const offStatus = room.onStatus(setStatus);
1097
+ const offRoster = room.onParticipants((next) => {
1098
+ setParticipants(next);
1099
+ sync(room);
1100
+ });
1101
+ const offError = room.onError(setError);
1102
+ return () => {
1103
+ offStatus();
1104
+ offRoster();
1105
+ offError();
1106
+ if (joined.current) {
1107
+ joined.current = false;
1108
+ room.leave();
1109
+ }
1110
+ };
1111
+ }, [room, sync]);
1112
+ const join = useCallback(async () => {
1113
+ if (!room) return false;
1114
+ setError(null);
1115
+ try {
1116
+ const connected = await room.join();
1117
+ joined.current = connected;
1118
+ setSfuAvailable(connected);
1119
+ sync(room);
1120
+ return connected;
1121
+ } catch (err) {
1122
+ setError(err instanceof Error ? err : new Error(String(err)));
1123
+ setSfuAvailable(true);
1124
+ return false;
1125
+ }
1126
+ }, [room, sync]);
1127
+ const leave = useCallback(() => {
1128
+ if (!joined.current) return;
1129
+ joined.current = false;
1130
+ room?.leave();
1131
+ }, [room]);
1132
+ const setCameraEnabled = useCallback(
1133
+ async (enabled) => {
1134
+ if (!room) return;
1135
+ await room.setCameraEnabled(enabled);
1136
+ sync(room);
1137
+ },
1138
+ [room, sync]
1139
+ );
1140
+ const setMicrophoneEnabled = useCallback(
1141
+ async (enabled) => {
1142
+ if (!room) return;
1143
+ await room.setMicrophoneEnabled(enabled);
1144
+ sync(room);
1145
+ },
1146
+ [room, sync]
1147
+ );
1148
+ const toggleCamera = useCallback(async () => {
1149
+ if (!room) return;
1150
+ await setCameraEnabled(!room.isCameraEnabled());
1151
+ }, [room, setCameraEnabled]);
1152
+ const toggleMic = useCallback(async () => {
1153
+ if (!room) return;
1154
+ await setMicrophoneEnabled(!room.isMicrophoneEnabled());
1155
+ }, [room, setMicrophoneEnabled]);
1156
+ return {
1157
+ status,
1158
+ participants,
1159
+ cameraEnabled,
1160
+ micEnabled,
1161
+ error,
1162
+ sfuAvailable,
1163
+ join,
1164
+ leave,
1165
+ setCameraEnabled,
1166
+ toggleCamera,
1167
+ setMicrophoneEnabled,
1168
+ toggleMic
1169
+ };
1170
+ }
1065
1171
  function useVoiceRoom(conversationId, opts = {}) {
1066
1172
  const poolse = usePoolse();
1067
1173
  const [status, setStatus] = useState("idle");
@@ -1176,11 +1282,11 @@ function useCalls(userId, opts = {}) {
1176
1282
  };
1177
1283
  }, [calls]);
1178
1284
  const call = useCallback(
1179
- async (conversationId) => {
1285
+ async (conversationId, media2 = "audio") => {
1180
1286
  if (!calls) return;
1181
1287
  setError(null);
1182
1288
  try {
1183
- const placed = await calls.invite(conversationId);
1289
+ const placed = await calls.invite(conversationId, media2);
1184
1290
  setOutgoing(placed);
1185
1291
  setPhase("ringing-out");
1186
1292
  } catch (err) {
@@ -1271,11 +1377,13 @@ function useCalls(userId, opts = {}) {
1271
1377
  setActiveConversationId(null);
1272
1378
  setError(null);
1273
1379
  }, []);
1380
+ const media = incoming?.media ?? outgoing?.media ?? "audio";
1274
1381
  return {
1275
1382
  phase,
1276
1383
  incoming,
1277
1384
  outgoing,
1278
1385
  activeConversationId,
1386
+ media,
1279
1387
  error,
1280
1388
  call,
1281
1389
  accept,
@@ -1286,6 +1394,6 @@ function useCalls(userId, opts = {}) {
1286
1394
  };
1287
1395
  }
1288
1396
 
1289
- export { PoolseProvider, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
1397
+ export { PoolseProvider, computeGroupPosition, formatDayLabel, sameDay, sameGroup, useAttachmentUpload, useAttachmentUrl, useCallRoom, useCalls, useConversation, useConversations, useMe, useMembers, useMessages, usePoolse, usePresence, useReactions, useRealtimeStatus, useThread, useTyping, useUser, useVoiceRoom };
1290
1398
  //# sourceMappingURL=index.js.map
1291
1399
  //# sourceMappingURL=index.js.map