@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.cjs +97 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -25
- package/dist/index.d.ts +144 -25
- package/dist/index.js +97 -27
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
-
*
|
|
1102
|
+
* Bridges iOS PushKit + CallKit to poolse calls, so a call rings a
|
|
1103
|
+
* backgrounded or closed app.
|
|
1031
1104
|
*
|
|
1032
|
-
*
|
|
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
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1171
|
+
* Registers this device for VoIP pushes and wires the native call UI.
|
|
1052
1172
|
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
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
|
|
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
|
-
*
|
|
1102
|
+
* Bridges iOS PushKit + CallKit to poolse calls, so a call rings a
|
|
1103
|
+
* backgrounded or closed app.
|
|
1031
1104
|
*
|
|
1032
|
-
*
|
|
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
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1171
|
+
* Registers this device for VoIP pushes and wires the native call UI.
|
|
1052
1172
|
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
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
|
|
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
|
-
|
|
4919
|
-
function
|
|
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
|
|
4929
|
-
|
|
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
|
|
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
|
|
4930
|
+
return new rtc.RTCPeerConnection({ iceServers });
|
|
4941
4931
|
},
|
|
4942
4932
|
getUserMedia() {
|
|
4943
|
-
return
|
|
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({
|
|
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
|