@poolse/react-native 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -977,8 +977,74 @@ declare const defaultDarkTheme: PoolseRNTheme;
977
977
  */
978
978
  declare function useAppStateLifecycle(): void;
979
979
 
980
+ /**
981
+ * React Native WebRTC binding, backed by `react-native-webrtc`.
982
+ *
983
+ * The module is passed IN rather than required here, and that is
984
+ * deliberate. Metro resolves dependencies statically, and this package
985
+ * is published through tsup, which rewrites a literal `require(...)`
986
+ * into a `__require(...)` call it cannot see — so bundling
987
+ * `react-native-webrtc` from inside this file never worked. It wasn't
988
+ * merely unavailable in Expo Go; it was absent from every bundle,
989
+ * development builds included, and surfaced as
990
+ * "Requiring unknown module react-native-webrtc" at runtime.
991
+ *
992
+ * Importing it in the app fixes that: Metro sees a static import in
993
+ * your source and bundles it. Optionality then lives where it belongs —
994
+ * an app that doesn't want voice simply never imports it, and never
995
+ * installs the native dependency.
996
+ *
997
+ * import * as webrtc from 'react-native-webrtc';
998
+ * <VoiceRoomBar conversationId={id} webrtc={webrtc} />
999
+ *
1000
+ * Media streams on native aren't attached to an element the way they
1001
+ * are on the web — audio-only calls route to the device's audio session
1002
+ * once the peer connection is live, so the sink is a no-op. Video would
1003
+ * render the stream through `<RTCView>` via the `toURL()` it exposes.
1004
+ */
1005
+
1006
+ /**
1007
+ * The shape this binding needs from `react-native-webrtc`. The module's
1008
+ * own namespace satisfies it, so `import * as webrtc` type-checks
1009
+ * straight through.
1010
+ */
1011
+ interface NativeWebRtcModule {
1012
+ RTCPeerConnection: new (...args: never[]) => unknown;
1013
+ mediaDevices: {
1014
+ getUserMedia: (...args: never[]) => Promise<unknown>;
1015
+ };
1016
+ }
1017
+ /**
1018
+ * True when `mod` looks like a usable `react-native-webrtc`.
1019
+ *
1020
+ * Guards against a half-linked native module: in a bare Expo Go client
1021
+ * the JS may load while the native side is missing, leaving
1022
+ * `RTCPeerConnection` undefined.
1023
+ */
1024
+ declare function isNativeWebRtcAvailable(mod: NativeWebRtcModule | null | undefined): boolean;
1025
+ /**
1026
+ * Adapter for `useVoiceRoom`'s `webrtc` option.
1027
+ *
1028
+ * @param mod the `react-native-webrtc` module, imported by your app.
1029
+ * @throws when `mod` isn't a usable binding — check
1030
+ * {@link isNativeWebRtcAvailable} first if that's reachable in
1031
+ * your UI.
1032
+ */
1033
+ declare function createNativeWebRtcAdapter(mod: NativeWebRtcModule): WebRtcAdapter;
1034
+
980
1035
  interface VoiceRoomBarProps {
981
1036
  conversationId: string;
1037
+ /**
1038
+ * The `react-native-webrtc` module, imported by your app:
1039
+ *
1040
+ * import * as webrtc from 'react-native-webrtc';
1041
+ *
1042
+ * Required for audio. Metro only bundles what it can see statically,
1043
+ * so this package cannot import it for you — see `voice/webrtc-native`.
1044
+ * Omit it and the bar renders its unavailable state, which is what you
1045
+ * want in Expo Go.
1046
+ */
1047
+ webrtc?: NativeWebRtcModule | null;
982
1048
  /** Resolves a user id to a display label. Defaults to a short id. */
983
1049
  labelFor?: (userId: string) => string;
984
1050
  /**
@@ -995,7 +1061,7 @@ interface VoiceRoomBarProps {
995
1061
  * always-on voice channel. For ringing a specific person, use
996
1062
  * `<IncomingCallSheet>` together with `useCalls`.
997
1063
  */
998
- declare function VoiceRoomBar({ conversationId, labelFor, unavailableSlot }: VoiceRoomBarProps): react_jsx_runtime.JSX.Element;
1064
+ declare function VoiceRoomBar({ conversationId, labelFor, unavailableSlot, webrtc, }: VoiceRoomBarProps): react_jsx_runtime.JSX.Element;
999
1065
 
1000
1066
  interface CallScreenProps {
1001
1067
  /** The signed-in user's id — the topic calls are delivered on. */
@@ -1008,6 +1074,12 @@ interface CallScreenProps {
1008
1074
  * component manages its own.
1009
1075
  */
1010
1076
  calls?: UseCalls;
1077
+ /**
1078
+ * The `react-native-webrtc` module, imported by your app. Required for
1079
+ * call audio; without it the screen still rings and connects but warns
1080
+ * that there is no audio. See {@link VoiceRoomBarProps.webrtc}.
1081
+ */
1082
+ webrtc?: NativeWebRtcModule | null;
1011
1083
  }
1012
1084
  /**
1013
1085
  * WhatsApp-style call UI: a full-screen sheet that covers the app while
@@ -1024,36 +1096,83 @@ interface CallScreenProps {
1024
1096
  * to whatever button your UI wants. Pass the same instance in via
1025
1097
  * `calls` so both halves share one state machine.
1026
1098
  */
1027
- declare function CallScreen({ userId, labelFor, calls: external }: CallScreenProps): react_jsx_runtime.JSX.Element;
1099
+ declare function CallScreen({ userId, labelFor, calls: external, webrtc }: CallScreenProps): react_jsx_runtime.JSX.Element;
1028
1100
 
1029
1101
  /**
1030
- * React Native WebRTC binding, backed by `react-native-webrtc`.
1102
+ * Bridges iOS PushKit + CallKit to poolse calls, so a call rings a
1103
+ * backgrounded or closed app.
1031
1104
  *
1032
- * That package ships native code, so it can't run in Expo Go and not
1033
- * every app wants it. It's therefore an OPTIONAL peer dependency,
1034
- * resolved with a guarded `require` at call time rather than a static
1035
- * import: an app that never places a call doesn't need it installed,
1036
- * and one that does gets a clear message instead of a redbox at import.
1105
+ * ## Why this is needed at all
1037
1106
  *
1038
- * Media streams on native aren't attached to an element the way they
1039
- * are on the web — audio-only calls route to the device's audio session
1040
- * automatically once the peer connection is live, so the sink is a
1041
- * no-op. Video would render the stream through `<RTCView>` using the
1042
- * `toURL()` the stream exposes.
1043
- */
1044
-
1045
- /**
1046
- * Whether this app can actually carry call audio. Use it to disable a
1047
- * call button rather than letting the user tap into a failure.
1107
+ * `call:incoming` travels over the WebSocket, which only exists while
1108
+ * the app is foregrounded — iOS suspends sockets on background and
1109
+ * drops them on close. Reaching a sleeping phone requires the OS to wake
1110
+ * the app, which means a VoIP push against a PushKit token.
1111
+ *
1112
+ * ## The rule Apple enforces
1113
+ *
1114
+ * Every delivered VoIP push MUST report an incoming call to CallKit,
1115
+ * essentially immediately. Miss it and iOS terminates the app; do it
1116
+ * repeatedly and the system stops delivering VoIP pushes to you at all.
1117
+ * `reportCall` below is not optional politeness — it is the contract.
1118
+ *
1119
+ * ## Dependencies
1120
+ *
1121
+ * `react-native-voip-push-notification` and `react-native-callkeep`,
1122
+ * both native, both requiring a development build. Like
1123
+ * `react-native-webrtc`, Metro only bundles what it can see statically,
1124
+ * so YOUR APP imports them and passes them in:
1125
+ *
1126
+ * import VoipPushNotification from 'react-native-voip-push-notification';
1127
+ * import RNCallKeep from 'react-native-callkeep';
1128
+ *
1129
+ * useVoipCalls({
1130
+ * voipPush: VoipPushNotification,
1131
+ * callKeep: RNCallKeep,
1132
+ * onAnswer: (call) => { ... },
1133
+ * });
1048
1134
  */
1049
- declare function isNativeWebRtcAvailable(): boolean;
1135
+ /** The slice of `react-native-voip-push-notification` used here. */
1136
+ interface VoipPushModule {
1137
+ addEventListener(event: 'register' | 'notification' | 'didLoadWithEvents', handler: (payload: never) => void): void;
1138
+ removeEventListener(event: string): void;
1139
+ registerVoipToken(): void;
1140
+ }
1141
+ /** The slice of `react-native-callkeep` used here. */
1142
+ interface CallKeepModule {
1143
+ setup(options: unknown): Promise<void>;
1144
+ displayIncomingCall(uuid: string, handle: string, localizedCallerName?: string, handleType?: string, hasVideo?: boolean): void;
1145
+ endCall(uuid: string): void;
1146
+ addEventListener(event: string, handler: (payload: never) => void): void;
1147
+ removeEventListener(event: string): void;
1148
+ }
1149
+ /** An inbound call, as it arrives inside a VoIP push payload. */
1150
+ interface VoipIncomingCall {
1151
+ callId: string;
1152
+ conversationId: string;
1153
+ callerUserId: string;
1154
+ callerName: string;
1155
+ }
1156
+ interface UseVoipCallsOptions {
1157
+ voipPush: VoipPushModule;
1158
+ callKeep: CallKeepModule;
1159
+ /**
1160
+ * Fired when the user answers from the native call UI. Accept the
1161
+ * call and join the room here — the app may have been launched cold,
1162
+ * so don't assume any prior state.
1163
+ */
1164
+ onAnswer?: (call: VoipIncomingCall) => void;
1165
+ /** Fired when the user declines from the native call UI. */
1166
+ onDecline?: (call: VoipIncomingCall) => void;
1167
+ /** CallKit display name for your app. Shown on the lock screen. */
1168
+ appName?: string;
1169
+ }
1050
1170
  /**
1051
- * Adapter for {@link useVoiceRoom}'s `webrtc` option.
1171
+ * Registers this device for VoIP pushes and wires the native call UI.
1052
1172
  *
1053
- * @throws when `react-native-webrtc` isn't installed — check
1054
- * {@link isNativeWebRtcAvailable} first if that's reachable in
1055
- * your UI.
1173
+ * Safe to mount once at the app root. Does nothing on Android, which
1174
+ * needs a separate FCM + ConnectionService integration.
1056
1175
  */
1057
- declare function createNativeWebRtcAdapter(): WebRtcAdapter;
1176
+ declare function useVoipCalls({ voipPush, callKeep, onAnswer, onDecline, appName, }: UseVoipCallsOptions): void;
1058
1177
 
1059
- export { AttachmentPicker, type AttachmentPickerProps, AttachmentPreview, type AttachmentPreviewProps, Avatar, type AvatarProps, CallScreen, type CallScreenProps, ChatHeader, type ChatHeaderProps, ConversationList, type ConversationListProps, ConversationView, type ConversationViewProps, DaySeparator, type DaySeparatorProps, GroupDetailsSheet, type GroupDetailsSheetProps, type IconName, ImageMosaic, type ImageMosaicProps, type InboxUser, MemberList, type MemberListProps, MentionInput, type MentionInputProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerProps, MessageList, type MessageListItem, type MessageListProps, MessageRow, type MessageRowProps, PoolseIcon, type PoolseIconProps, PoolseInbox, type PoolseInboxHandle, type PoolseInboxProps, PoolseLogo, type PoolseLogoProps, type PoolseLogoVariant, type PoolseRNTheme, type PoolseRNThemeOverrides, PoolseTheme, type PoolseThemeProps, primitives as Primitives, ReactionPicker, type ReactionPickerProps, ReactionStrip, type ReactionStripProps, type ThemeColors, type ThemeRadii, type ThemeShadows, type ThemeSpacing, type ThemeType, ThreadView, type ThreadViewProps, TypingIndicator, type TypingIndicatorProps, UploadQueueStrip, UserName, type UserNameProps, VoiceRoomBar, type VoiceRoomBarProps, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme };
1178
+ export { AttachmentPicker, type AttachmentPickerProps, AttachmentPreview, type AttachmentPreviewProps, Avatar, type AvatarProps, type CallKeepModule, CallScreen, type CallScreenProps, ChatHeader, type ChatHeaderProps, ConversationList, type ConversationListProps, ConversationView, type ConversationViewProps, DaySeparator, type DaySeparatorProps, GroupDetailsSheet, type GroupDetailsSheetProps, type IconName, ImageMosaic, type ImageMosaicProps, type InboxUser, MemberList, type MemberListProps, MentionInput, type MentionInputProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerProps, MessageList, type MessageListItem, type MessageListProps, MessageRow, type MessageRowProps, type NativeWebRtcModule, PoolseIcon, type PoolseIconProps, PoolseInbox, type PoolseInboxHandle, type PoolseInboxProps, PoolseLogo, type PoolseLogoProps, type PoolseLogoVariant, type PoolseRNTheme, type PoolseRNThemeOverrides, PoolseTheme, type PoolseThemeProps, primitives as Primitives, ReactionPicker, type ReactionPickerProps, ReactionStrip, type ReactionStripProps, type ThemeColors, type ThemeRadii, type ThemeShadows, type ThemeSpacing, type ThemeType, ThreadView, type ThreadViewProps, TypingIndicator, type TypingIndicatorProps, UploadQueueStrip, type UseVoipCallsOptions, UserName, type UserNameProps, VoiceRoomBar, type VoiceRoomBarProps, type VoipIncomingCall, type VoipPushModule, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme, useVoipCalls };
package/dist/index.d.ts CHANGED
@@ -977,8 +977,74 @@ declare const defaultDarkTheme: PoolseRNTheme;
977
977
  */
978
978
  declare function useAppStateLifecycle(): void;
979
979
 
980
+ /**
981
+ * React Native WebRTC binding, backed by `react-native-webrtc`.
982
+ *
983
+ * The module is passed IN rather than required here, and that is
984
+ * deliberate. Metro resolves dependencies statically, and this package
985
+ * is published through tsup, which rewrites a literal `require(...)`
986
+ * into a `__require(...)` call it cannot see — so bundling
987
+ * `react-native-webrtc` from inside this file never worked. It wasn't
988
+ * merely unavailable in Expo Go; it was absent from every bundle,
989
+ * development builds included, and surfaced as
990
+ * "Requiring unknown module react-native-webrtc" at runtime.
991
+ *
992
+ * Importing it in the app fixes that: Metro sees a static import in
993
+ * your source and bundles it. Optionality then lives where it belongs —
994
+ * an app that doesn't want voice simply never imports it, and never
995
+ * installs the native dependency.
996
+ *
997
+ * import * as webrtc from 'react-native-webrtc';
998
+ * <VoiceRoomBar conversationId={id} webrtc={webrtc} />
999
+ *
1000
+ * Media streams on native aren't attached to an element the way they
1001
+ * are on the web — audio-only calls route to the device's audio session
1002
+ * once the peer connection is live, so the sink is a no-op. Video would
1003
+ * render the stream through `<RTCView>` via the `toURL()` it exposes.
1004
+ */
1005
+
1006
+ /**
1007
+ * The shape this binding needs from `react-native-webrtc`. The module's
1008
+ * own namespace satisfies it, so `import * as webrtc` type-checks
1009
+ * straight through.
1010
+ */
1011
+ interface NativeWebRtcModule {
1012
+ RTCPeerConnection: new (...args: never[]) => unknown;
1013
+ mediaDevices: {
1014
+ getUserMedia: (...args: never[]) => Promise<unknown>;
1015
+ };
1016
+ }
1017
+ /**
1018
+ * True when `mod` looks like a usable `react-native-webrtc`.
1019
+ *
1020
+ * Guards against a half-linked native module: in a bare Expo Go client
1021
+ * the JS may load while the native side is missing, leaving
1022
+ * `RTCPeerConnection` undefined.
1023
+ */
1024
+ declare function isNativeWebRtcAvailable(mod: NativeWebRtcModule | null | undefined): boolean;
1025
+ /**
1026
+ * Adapter for `useVoiceRoom`'s `webrtc` option.
1027
+ *
1028
+ * @param mod the `react-native-webrtc` module, imported by your app.
1029
+ * @throws when `mod` isn't a usable binding — check
1030
+ * {@link isNativeWebRtcAvailable} first if that's reachable in
1031
+ * your UI.
1032
+ */
1033
+ declare function createNativeWebRtcAdapter(mod: NativeWebRtcModule): WebRtcAdapter;
1034
+
980
1035
  interface VoiceRoomBarProps {
981
1036
  conversationId: string;
1037
+ /**
1038
+ * The `react-native-webrtc` module, imported by your app:
1039
+ *
1040
+ * import * as webrtc from 'react-native-webrtc';
1041
+ *
1042
+ * Required for audio. Metro only bundles what it can see statically,
1043
+ * so this package cannot import it for you — see `voice/webrtc-native`.
1044
+ * Omit it and the bar renders its unavailable state, which is what you
1045
+ * want in Expo Go.
1046
+ */
1047
+ webrtc?: NativeWebRtcModule | null;
982
1048
  /** Resolves a user id to a display label. Defaults to a short id. */
983
1049
  labelFor?: (userId: string) => string;
984
1050
  /**
@@ -995,7 +1061,7 @@ interface VoiceRoomBarProps {
995
1061
  * always-on voice channel. For ringing a specific person, use
996
1062
  * `<IncomingCallSheet>` together with `useCalls`.
997
1063
  */
998
- declare function VoiceRoomBar({ conversationId, labelFor, unavailableSlot }: VoiceRoomBarProps): react_jsx_runtime.JSX.Element;
1064
+ declare function VoiceRoomBar({ conversationId, labelFor, unavailableSlot, webrtc, }: VoiceRoomBarProps): react_jsx_runtime.JSX.Element;
999
1065
 
1000
1066
  interface CallScreenProps {
1001
1067
  /** The signed-in user's id — the topic calls are delivered on. */
@@ -1008,6 +1074,12 @@ interface CallScreenProps {
1008
1074
  * component manages its own.
1009
1075
  */
1010
1076
  calls?: UseCalls;
1077
+ /**
1078
+ * The `react-native-webrtc` module, imported by your app. Required for
1079
+ * call audio; without it the screen still rings and connects but warns
1080
+ * that there is no audio. See {@link VoiceRoomBarProps.webrtc}.
1081
+ */
1082
+ webrtc?: NativeWebRtcModule | null;
1011
1083
  }
1012
1084
  /**
1013
1085
  * WhatsApp-style call UI: a full-screen sheet that covers the app while
@@ -1024,36 +1096,83 @@ interface CallScreenProps {
1024
1096
  * to whatever button your UI wants. Pass the same instance in via
1025
1097
  * `calls` so both halves share one state machine.
1026
1098
  */
1027
- declare function CallScreen({ userId, labelFor, calls: external }: CallScreenProps): react_jsx_runtime.JSX.Element;
1099
+ declare function CallScreen({ userId, labelFor, calls: external, webrtc }: CallScreenProps): react_jsx_runtime.JSX.Element;
1028
1100
 
1029
1101
  /**
1030
- * React Native WebRTC binding, backed by `react-native-webrtc`.
1102
+ * Bridges iOS PushKit + CallKit to poolse calls, so a call rings a
1103
+ * backgrounded or closed app.
1031
1104
  *
1032
- * That package ships native code, so it can't run in Expo Go and not
1033
- * every app wants it. It's therefore an OPTIONAL peer dependency,
1034
- * resolved with a guarded `require` at call time rather than a static
1035
- * import: an app that never places a call doesn't need it installed,
1036
- * and one that does gets a clear message instead of a redbox at import.
1105
+ * ## Why this is needed at all
1037
1106
  *
1038
- * Media streams on native aren't attached to an element the way they
1039
- * are on the web — audio-only calls route to the device's audio session
1040
- * automatically once the peer connection is live, so the sink is a
1041
- * no-op. Video would render the stream through `<RTCView>` using the
1042
- * `toURL()` the stream exposes.
1043
- */
1044
-
1045
- /**
1046
- * Whether this app can actually carry call audio. Use it to disable a
1047
- * call button rather than letting the user tap into a failure.
1107
+ * `call:incoming` travels over the WebSocket, which only exists while
1108
+ * the app is foregrounded — iOS suspends sockets on background and
1109
+ * drops them on close. Reaching a sleeping phone requires the OS to wake
1110
+ * the app, which means a VoIP push against a PushKit token.
1111
+ *
1112
+ * ## The rule Apple enforces
1113
+ *
1114
+ * Every delivered VoIP push MUST report an incoming call to CallKit,
1115
+ * essentially immediately. Miss it and iOS terminates the app; do it
1116
+ * repeatedly and the system stops delivering VoIP pushes to you at all.
1117
+ * `reportCall` below is not optional politeness — it is the contract.
1118
+ *
1119
+ * ## Dependencies
1120
+ *
1121
+ * `react-native-voip-push-notification` and `react-native-callkeep`,
1122
+ * both native, both requiring a development build. Like
1123
+ * `react-native-webrtc`, Metro only bundles what it can see statically,
1124
+ * so YOUR APP imports them and passes them in:
1125
+ *
1126
+ * import VoipPushNotification from 'react-native-voip-push-notification';
1127
+ * import RNCallKeep from 'react-native-callkeep';
1128
+ *
1129
+ * useVoipCalls({
1130
+ * voipPush: VoipPushNotification,
1131
+ * callKeep: RNCallKeep,
1132
+ * onAnswer: (call) => { ... },
1133
+ * });
1048
1134
  */
1049
- declare function isNativeWebRtcAvailable(): boolean;
1135
+ /** The slice of `react-native-voip-push-notification` used here. */
1136
+ interface VoipPushModule {
1137
+ addEventListener(event: 'register' | 'notification' | 'didLoadWithEvents', handler: (payload: never) => void): void;
1138
+ removeEventListener(event: string): void;
1139
+ registerVoipToken(): void;
1140
+ }
1141
+ /** The slice of `react-native-callkeep` used here. */
1142
+ interface CallKeepModule {
1143
+ setup(options: unknown): Promise<void>;
1144
+ displayIncomingCall(uuid: string, handle: string, localizedCallerName?: string, handleType?: string, hasVideo?: boolean): void;
1145
+ endCall(uuid: string): void;
1146
+ addEventListener(event: string, handler: (payload: never) => void): void;
1147
+ removeEventListener(event: string): void;
1148
+ }
1149
+ /** An inbound call, as it arrives inside a VoIP push payload. */
1150
+ interface VoipIncomingCall {
1151
+ callId: string;
1152
+ conversationId: string;
1153
+ callerUserId: string;
1154
+ callerName: string;
1155
+ }
1156
+ interface UseVoipCallsOptions {
1157
+ voipPush: VoipPushModule;
1158
+ callKeep: CallKeepModule;
1159
+ /**
1160
+ * Fired when the user answers from the native call UI. Accept the
1161
+ * call and join the room here — the app may have been launched cold,
1162
+ * so don't assume any prior state.
1163
+ */
1164
+ onAnswer?: (call: VoipIncomingCall) => void;
1165
+ /** Fired when the user declines from the native call UI. */
1166
+ onDecline?: (call: VoipIncomingCall) => void;
1167
+ /** CallKit display name for your app. Shown on the lock screen. */
1168
+ appName?: string;
1169
+ }
1050
1170
  /**
1051
- * Adapter for {@link useVoiceRoom}'s `webrtc` option.
1171
+ * Registers this device for VoIP pushes and wires the native call UI.
1052
1172
  *
1053
- * @throws when `react-native-webrtc` isn't installed — check
1054
- * {@link isNativeWebRtcAvailable} first if that's reachable in
1055
- * your UI.
1173
+ * Safe to mount once at the app root. Does nothing on Android, which
1174
+ * needs a separate FCM + ConnectionService integration.
1056
1175
  */
1057
- declare function createNativeWebRtcAdapter(): WebRtcAdapter;
1176
+ declare function useVoipCalls({ voipPush, callKeep, onAnswer, onDecline, appName, }: UseVoipCallsOptions): void;
1058
1177
 
1059
- export { AttachmentPicker, type AttachmentPickerProps, AttachmentPreview, type AttachmentPreviewProps, Avatar, type AvatarProps, CallScreen, type CallScreenProps, ChatHeader, type ChatHeaderProps, ConversationList, type ConversationListProps, ConversationView, type ConversationViewProps, DaySeparator, type DaySeparatorProps, GroupDetailsSheet, type GroupDetailsSheetProps, type IconName, ImageMosaic, type ImageMosaicProps, type InboxUser, MemberList, type MemberListProps, MentionInput, type MentionInputProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerProps, MessageList, type MessageListItem, type MessageListProps, MessageRow, type MessageRowProps, PoolseIcon, type PoolseIconProps, PoolseInbox, type PoolseInboxHandle, type PoolseInboxProps, PoolseLogo, type PoolseLogoProps, type PoolseLogoVariant, type PoolseRNTheme, type PoolseRNThemeOverrides, PoolseTheme, type PoolseThemeProps, primitives as Primitives, ReactionPicker, type ReactionPickerProps, ReactionStrip, type ReactionStripProps, type ThemeColors, type ThemeRadii, type ThemeShadows, type ThemeSpacing, type ThemeType, ThreadView, type ThreadViewProps, TypingIndicator, type TypingIndicatorProps, UploadQueueStrip, UserName, type UserNameProps, VoiceRoomBar, type VoiceRoomBarProps, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme };
1178
+ export { AttachmentPicker, type AttachmentPickerProps, AttachmentPreview, type AttachmentPreviewProps, Avatar, type AvatarProps, type CallKeepModule, CallScreen, type CallScreenProps, ChatHeader, type ChatHeaderProps, ConversationList, type ConversationListProps, ConversationView, type ConversationViewProps, DaySeparator, type DaySeparatorProps, GroupDetailsSheet, type GroupDetailsSheetProps, type IconName, ImageMosaic, type ImageMosaicProps, type InboxUser, MemberList, type MemberListProps, MentionInput, type MentionInputProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerProps, MessageList, type MessageListItem, type MessageListProps, MessageRow, type MessageRowProps, type NativeWebRtcModule, PoolseIcon, type PoolseIconProps, PoolseInbox, type PoolseInboxHandle, type PoolseInboxProps, PoolseLogo, type PoolseLogoProps, type PoolseLogoVariant, type PoolseRNTheme, type PoolseRNThemeOverrides, PoolseTheme, type PoolseThemeProps, primitives as Primitives, ReactionPicker, type ReactionPickerProps, ReactionStrip, type ReactionStripProps, type ThemeColors, type ThemeRadii, type ThemeShadows, type ThemeSpacing, type ThemeType, ThreadView, type ThreadViewProps, TypingIndicator, type TypingIndicatorProps, UploadQueueStrip, type UseVoipCallsOptions, UserName, type UserNameProps, VoiceRoomBar, type VoiceRoomBarProps, type VoipIncomingCall, type VoipPushModule, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme, useVoipCalls };
package/dist/index.js CHANGED
@@ -4915,32 +4915,22 @@ function useAppStateLifecycle() {
4915
4915
  }
4916
4916
 
4917
4917
  // src/voice/webrtc-native.ts
4918
- var cached;
4919
- function loadNativeWebRtc() {
4920
- if (cached !== void 0) return cached;
4921
- try {
4922
- cached = __require("react-native-webrtc");
4923
- } catch {
4924
- cached = null;
4925
- }
4926
- return cached;
4918
+ function isNativeWebRtcAvailable(mod) {
4919
+ return typeof mod?.RTCPeerConnection === "function" && mod?.mediaDevices != null;
4927
4920
  }
4928
- function isNativeWebRtcAvailable() {
4929
- return loadNativeWebRtc() != null;
4930
- }
4931
- function createNativeWebRtcAdapter() {
4932
- const native = loadNativeWebRtc();
4933
- if (!native) {
4921
+ function createNativeWebRtcAdapter(mod) {
4922
+ if (!isNativeWebRtcAvailable(mod)) {
4934
4923
  throw new Error(
4935
- "react-native-webrtc is not installed. Add it to enable poolse voice calls:\n npx expo install react-native-webrtc\nIt contains native code, so it needs a development build \u2014 it will not run in Expo Go."
4924
+ "react-native-webrtc is missing or not linked. Install it and rebuild:\n npx expo install react-native-webrtc\nIt contains native code, so it needs a development build \u2014 it will not run in Expo Go."
4936
4925
  );
4937
4926
  }
4927
+ const rtc = mod;
4938
4928
  return {
4939
4929
  createPeerConnection(iceServers) {
4940
- return new native.RTCPeerConnection({ iceServers });
4930
+ return new rtc.RTCPeerConnection({ iceServers });
4941
4931
  },
4942
4932
  getUserMedia() {
4943
- return native.mediaDevices.getUserMedia({
4933
+ return rtc.mediaDevices.getUserMedia({
4944
4934
  audio: { echoCancellation: true, noiseSuppression: true },
4945
4935
  video: false
4946
4936
  });
@@ -4951,12 +4941,17 @@ function createNativeWebRtcAdapter() {
4951
4941
  }
4952
4942
  };
4953
4943
  }
4954
- function VoiceRoomBar({ conversationId, labelFor, unavailableSlot }) {
4944
+ function VoiceRoomBar({
4945
+ conversationId,
4946
+ labelFor,
4947
+ unavailableSlot,
4948
+ webrtc
4949
+ }) {
4955
4950
  const theme = usePoolseTheme();
4956
- const available = isNativeWebRtcAvailable();
4951
+ const available = isNativeWebRtcAvailable(webrtc);
4957
4952
  const opts = useMemo(
4958
- () => available ? { webrtc: createNativeWebRtcAdapter() } : {},
4959
- [available]
4953
+ () => available && webrtc ? { webrtc: createNativeWebRtcAdapter(webrtc) } : {},
4954
+ [available, webrtc]
4960
4955
  );
4961
4956
  const { status, participants, muted, join, leave, toggleMute, error } = useVoiceRoom(
4962
4957
  available ? conversationId : null,
@@ -5084,14 +5079,14 @@ var styles23 = StyleSheet.create({
5084
5079
  hint: { fontSize: 13, flexShrink: 1 },
5085
5080
  error: { fontSize: 12, marginTop: 6 }
5086
5081
  });
5087
- function CallScreen({ userId, labelFor, calls: external }) {
5082
+ function CallScreen({ userId, labelFor, calls: external, webrtc }) {
5088
5083
  const theme = usePoolseTheme();
5089
5084
  const own = useCalls(external ? null : userId);
5090
5085
  const calls = external ?? own;
5091
- const available = isNativeWebRtcAvailable();
5086
+ const available = isNativeWebRtcAvailable(webrtc);
5092
5087
  const opts = useMemo(
5093
- () => available ? { webrtc: createNativeWebRtcAdapter() } : {},
5094
- [available]
5088
+ () => available && webrtc ? { webrtc: createNativeWebRtcAdapter(webrtc) } : {},
5089
+ [available, webrtc]
5095
5090
  );
5096
5091
  const voice = useVoiceRoom(
5097
5092
  calls.phase === "active" && available ? calls.activeConversationId : null,
@@ -5199,7 +5194,82 @@ var styles24 = StyleSheet.create({
5199
5194
  callBtnText: { color: "#ffffff", fontSize: 16, fontWeight: "600" },
5200
5195
  warn: { fontSize: 12, textAlign: "center", marginTop: 12 }
5201
5196
  });
5197
+ function useVoipCalls({
5198
+ voipPush,
5199
+ callKeep,
5200
+ onAnswer,
5201
+ onDecline,
5202
+ appName = "poolse"
5203
+ }) {
5204
+ const poolse = usePoolse();
5205
+ const pending = useRef(/* @__PURE__ */ new Map());
5206
+ const handlers = useRef({ onAnswer, onDecline });
5207
+ handlers.current = { onAnswer, onDecline };
5208
+ useEffect(() => {
5209
+ let cancelled = false;
5210
+ const reportCall = (payload) => {
5211
+ const callId = payload.call_id;
5212
+ const conversationId = payload.conversation_id;
5213
+ if (!callId || !conversationId) return;
5214
+ const call = {
5215
+ callId,
5216
+ conversationId,
5217
+ callerUserId: payload.caller_user_id ?? "",
5218
+ callerName: payload.caller_name ?? "Incoming call"
5219
+ };
5220
+ pending.current.set(callId, call);
5221
+ callKeep.displayIncomingCall(callId, call.callerUserId, call.callerName, "generic", false);
5222
+ };
5223
+ void callKeep.setup({
5224
+ ios: { appName },
5225
+ android: {
5226
+ alertTitle: "Permissions required",
5227
+ alertDescription: "Allow calls from this app",
5228
+ cancelButton: "Cancel",
5229
+ okButton: "ok",
5230
+ additionalPermissions: []
5231
+ }
5232
+ }).catch(() => {
5233
+ });
5234
+ voipPush.addEventListener("register", ((token) => {
5235
+ if (cancelled || !token) return;
5236
+ void poolse.devices.register({ token, platform: "ios", environment: apnsEnvironment() }).catch(() => {
5237
+ });
5238
+ }));
5239
+ voipPush.addEventListener("notification", ((payload) => {
5240
+ reportCall(payload);
5241
+ }));
5242
+ voipPush.addEventListener("didLoadWithEvents", ((events) => {
5243
+ for (const event of events ?? []) {
5244
+ if (event.name === "RNVoipPushRemoteNotificationReceivedEvent") {
5245
+ reportCall(event.data);
5246
+ }
5247
+ }
5248
+ }));
5249
+ callKeep.addEventListener("answerCall", (({ callUUID }) => {
5250
+ const call = pending.current.get(callUUID);
5251
+ if (call) handlers.current.onAnswer?.(call);
5252
+ }));
5253
+ callKeep.addEventListener("endCall", (({ callUUID }) => {
5254
+ const call = pending.current.get(callUUID);
5255
+ pending.current.delete(callUUID);
5256
+ if (call) handlers.current.onDecline?.(call);
5257
+ }));
5258
+ voipPush.registerVoipToken();
5259
+ return () => {
5260
+ cancelled = true;
5261
+ voipPush.removeEventListener("register");
5262
+ voipPush.removeEventListener("notification");
5263
+ voipPush.removeEventListener("didLoadWithEvents");
5264
+ callKeep.removeEventListener("answerCall");
5265
+ callKeep.removeEventListener("endCall");
5266
+ };
5267
+ }, [poolse, voipPush, callKeep, appName]);
5268
+ }
5269
+ function apnsEnvironment() {
5270
+ return __DEV__ ? "sandbox" : "production";
5271
+ }
5202
5272
 
5203
- export { AttachmentPicker, AttachmentPreview, Avatar, CallScreen, ChatHeader, ConversationList, ConversationView, DaySeparator, GroupDetailsSheet, ImageMosaic, MemberList, MentionInput, MessageActions, MessageBubble, MessageComposer, MessageList, MessageRow, PoolseIcon, PoolseInbox, PoolseLogo, PoolseTheme, primitives as Primitives, ReactionPicker, ReactionStrip, ThreadView, TypingIndicator, UploadQueueStrip, UserName, VoiceRoomBar, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme };
5273
+ export { AttachmentPicker, AttachmentPreview, Avatar, CallScreen, ChatHeader, ConversationList, ConversationView, DaySeparator, GroupDetailsSheet, ImageMosaic, MemberList, MentionInput, MessageActions, MessageBubble, MessageComposer, MessageList, MessageRow, PoolseIcon, PoolseInbox, PoolseLogo, PoolseTheme, primitives as Primitives, ReactionPicker, ReactionStrip, ThreadView, TypingIndicator, UploadQueueStrip, UserName, VoiceRoomBar, createNativeWebRtcAdapter, defaultDarkTheme, defaultLightTheme, isNativeWebRtcAvailable, useAppStateLifecycle, useDisplayName, usePoolseTheme, useVoipCalls };
5204
5274
  //# sourceMappingURL=index.js.map
5205
5275
  //# sourceMappingURL=index.js.map