@appsocom/react-native 0.0.0-stage → 0.5.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Appsotech Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,25 @@
1
- # Temporary Holding Version
1
+ # @appsocom/react-native
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React Native client for [Appsocom Live](https://live.appsocom.com) video calls on iOS and Android: join rooms, camera and mic, video grid and controls, built on `react-native-webrtc`. It talks the same room protocol as the web and Flutter clients, so everyone can be in the same call.
4
+
5
+ ```bash
6
+ npm install @appsocom/react-native react-native-webrtc
7
+ ```
8
+
9
+ ```tsx
10
+ import { VideoConference, requestMediaPermissions } from "@appsocom/react-native";
11
+
12
+ await requestMediaPermissions(); // Android runtime permissions
13
+ <VideoConference url="https://api.appsocom.dev" token={token} onLeft={() => navigation.goBack()} />
14
+ ```
15
+
16
+ The same components and hooks exist as in `@appsocom/react`. Long-press a tile for teacher controls.
17
+
18
+ Setup:
19
+
20
+ - **iOS 13+:** add `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` to `Info.plist`, and the `audio` background mode to keep calls going in the background.
21
+ - **Android:** `CAMERA`, `RECORD_AUDIO`, `MODIFY_AUDIO_SETTINGS`, `INTERNET` and `ACCESS_NETWORK_STATE`, with `minSdkVersion` 24.
22
+
23
+ Guide: [UI kits](https://docs.appsocom.dev/ui-kits)
24
+
25
+ Docs: [docs.appsocom.dev](https://docs.appsocom.dev) · License: MIT
@@ -0,0 +1,2 @@
1
+ export * from "./room.js";
2
+ export * from "./session.js";
@@ -0,0 +1,5 @@
1
+ // Platform-neutral core: the room + SFU session, using whatever WebRTC
2
+ // implementation you pass in. No react-native imports.
3
+ export * from "./room.js";
4
+ export * from "./session.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,uDAAuD;AACvD,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * A Room for React Native (and anything else with standard WebRTC objects but
3
+ * no DOM). Same room protocol, events and method names as the web Room in
4
+ * @appsocom/client, so the @appsocom/react hooks work with both.
5
+ *
6
+ * Not available here (web only): screen sharing, background blur, noise
7
+ * suppression (use the OS voice processing), end-to-end encryption.
8
+ */
9
+ import { Emitter } from "@appsocom/client/emitter";
10
+ import { type ChatMessage, type ConnectionQuality, type Device, type JoinClaims, type Participant, type ParticipantState, type Permissions, type RecordingStatus, type RoomState, type TrackKind, type TranscriptSegment, type VideoQuality, type DataSaverInput, type DataSaverMode, type DataSaverSettings, type DataUsage } from "@appsocom/protocol";
11
+ import { type WebRTCImpl } from "./session.js";
12
+ export declare const TOKEN_HEADER = "X-SfuKit-Token";
13
+ export interface NativeJoinOptions {
14
+ /** Where the kit's Worker routes live, e.g. "https://video.example.com". */
15
+ url: string;
16
+ /** Join token from your backend. */
17
+ token: string;
18
+ /** Start with the mic on. Default true. */
19
+ audio?: boolean;
20
+ /** Start with the camera on. Default true. */
21
+ video?: boolean;
22
+ /** "user" (front, default) or "environment" (back) camera. */
23
+ facingMode?: "user" | "environment";
24
+ /** Send the camera in three sizes so each viewer gets what it needs. Default true. */
25
+ simulcast?: boolean;
26
+ /** Reconnect after network drops. Default true. */
27
+ reconnect?: boolean;
28
+ /** Give up reconnecting after this long, in ms. Default 120000. */
29
+ reconnectTimeoutMs?: number;
30
+ iceServers?: RTCIceServer[];
31
+ /** Default 15000. Paused while you're in a waiting room. */
32
+ joinTimeoutMs?: number;
33
+ /** Receive others' tracks automatically. Default true. `{ video: false }`: only what you setSubscribed(). */
34
+ autoSubscribe?: boolean | {
35
+ audio?: boolean;
36
+ video?: boolean;
37
+ };
38
+ /** Called when you're put in the waiting room. */
39
+ onWaiting?: () => void;
40
+ /**
41
+ * Audio-first fallback: on a very bad connection stop all camera video both
42
+ * ways and keep audio; video comes back by itself. Default true.
43
+ */
44
+ audioFallback?: boolean;
45
+ /** Data saver: "low", "minimal", "audio" or custom settings. Default: the token's, else "off". */
46
+ dataSaver?: DataSaverInput;
47
+ /** WebRTC implementation. React Native: set for you by @appsocom/react-native. */
48
+ webrtc?: WebRTCImpl;
49
+ /** Override fetch / WebSocket (tests). */
50
+ fetch?: typeof fetch;
51
+ WebSocket?: typeof WebSocket;
52
+ }
53
+ export type ConnectionState = "connecting" | "connected" | "reconnecting" | "disconnected";
54
+ export type NativeRoomEvents = {
55
+ "participant-joined": (participant: Participant) => void;
56
+ "participant-updated": (participant: Participant) => void;
57
+ "participant-left": (participant: Participant) => void;
58
+ track: (participant: Participant, kind: TrackKind, track: MediaStreamTrack) => void;
59
+ "track-removed": (participant: Participant, kind: TrackKind) => void;
60
+ "local-track": (kind: "video" | "screenVideo", track: MediaStreamTrack | null) => void;
61
+ "local-state": (state: ParticipantState) => void;
62
+ permissions: (permissions: Permissions, previous: Permissions) => void;
63
+ self: (self: Participant) => void;
64
+ role: (role: string, previous: string) => void;
65
+ muted: (devices: Device[], by: Participant | undefined) => void;
66
+ chat: (message: ChatMessage) => void;
67
+ "chat-deleted": (id: string) => void;
68
+ hands: (raised: Participant[]) => void;
69
+ waiting: () => void;
70
+ "group-changed": (group: string | null) => void;
71
+ "waiting-list": (waiting: Participant[]) => void;
72
+ "room-state": (state: RoomState) => void;
73
+ recording: (recording: RecordingStatus | null) => void;
74
+ message: (data: unknown, from: Participant | undefined) => void;
75
+ connection: (state: ConnectionState) => void;
76
+ "media-connection": (state: RTCPeerConnectionState) => void;
77
+ "connection-quality": (participantId: string, quality: ConnectionQuality) => void;
78
+ "active-speakers": (participantIds: string[]) => void;
79
+ "video-quality": (participant: Participant, quality: VideoQuality) => void;
80
+ "video-paused": (participant: Participant | null, paused: boolean) => void;
81
+ "audio-fallback": (active: boolean) => void;
82
+ "data-saver": (mode: DataSaverMode | "custom", settings: DataSaverSettings) => void;
83
+ "data-usage": (usage: DataUsage) => void;
84
+ transcript: (segment: TranscriptSegment) => void;
85
+ error: (error: Error) => void;
86
+ left: (reason: string) => void;
87
+ };
88
+ /** Join a room from React Native. Resolves once you're in. */
89
+ export declare function joinNativeRoom(options: NativeJoinOptions): Promise<NativeRoom>;
90
+ export declare class NativeRoom extends Emitter<NativeRoomEvents> {
91
+ #private;
92
+ readonly roomId: string;
93
+ readonly userId: string;
94
+ role: string;
95
+ permissions: Permissions;
96
+ self: Participant | null;
97
+ connectionState: ConnectionState;
98
+ roomState: RoomState;
99
+ waiting: Participant[];
100
+ chat: ChatMessage[];
101
+ recording: RecordingStatus | null;
102
+ /** @internal use joinNativeRoom() */
103
+ constructor(options: NativeJoinOptions);
104
+ get participants(): Participant[];
105
+ get localState(): ParticipantState;
106
+ get canPublish(): boolean;
107
+ get metadata(): Record<string, unknown> | undefined;
108
+ get raisedHands(): Participant[];
109
+ get agents(): Participant[];
110
+ get activeSpeakers(): string[];
111
+ /** Audio only by choice: setAudioOnly(true) or the "audio" data saver. See also audioFallback. */
112
+ get audioOnly(): boolean;
113
+ /** True while your connection has fallen back to audio only. */
114
+ get audioFallback(): boolean;
115
+ get dataSaver(): {
116
+ mode: DataSaverMode | "custom";
117
+ settings: DataSaverSettings;
118
+ };
119
+ /** Media data used in this call so far, current rates and MB per hour. */
120
+ get dataUsage(): DataUsage;
121
+ getConnectionQuality(participantId: string): ConnectionQuality | undefined;
122
+ getTrack(participantId: string, kind: TrackKind): MediaStreamTrack | undefined;
123
+ /** Your camera preview (null while off). Screen sharing isn't available on React Native. */
124
+ getLocalTrack(kind: "video" | "screenVideo"): MediaStreamTrack | null;
125
+ toggleMic(): void;
126
+ setMic(on: boolean): void;
127
+ toggleCamera(): void;
128
+ setCamera(on: boolean): void;
129
+ /** Flip between the front and back camera. */
130
+ switchCamera(): void;
131
+ /** Pick a specific mic/camera by device. */
132
+ setMicDevice(device: MediaDeviceInfo): void;
133
+ setCameraDevice(device: MediaDeviceInfo): void;
134
+ setCustomState(custom: Record<string, unknown>): void;
135
+ setPermissions(userId: string, permissions: Partial<Omit<Permissions, "moderate">>): void;
136
+ mute(userId: string, devices?: Device[], options?: {
137
+ lock?: boolean;
138
+ }): void;
139
+ muteAll(devices?: Device[], options?: {
140
+ lock?: boolean;
141
+ }): void;
142
+ stopScreenShare(userId: string): void;
143
+ remove(userId: string, options?: {
144
+ ban?: boolean;
145
+ }): void;
146
+ raiseHand(): void;
147
+ lowerHand(userId?: string): void;
148
+ lowerAllHands(): void;
149
+ sendChat(text: string, options?: {
150
+ to?: string;
151
+ everywhere?: boolean;
152
+ }): void;
153
+ deleteChat(id: string): void;
154
+ setChatEnabled(enabled: boolean): void;
155
+ setSpotlight(userIds: string[]): void;
156
+ setWaitingRoom(on: boolean): void;
157
+ lockRoom(locked?: boolean): void;
158
+ admit(userId: string): void;
159
+ deny(userId: string): void;
160
+ startRecording(options?: {
161
+ video?: boolean;
162
+ }): void;
163
+ stopRecording(): void;
164
+ sendToAgent(agentId: string, text: string): void;
165
+ /** App message to everyone else (room.on("message") on their side). */
166
+ send(data: unknown): void;
167
+ updateToken(token: string): void;
168
+ setSubscribed(participantId: string, kinds: TrackKind | TrackKind[], on: boolean): void;
169
+ isSubscribed(participantId: string, kind: TrackKind): boolean;
170
+ /** "high" | "medium" | "low" | "off" video from one participant. */
171
+ setVideoQuality(participantId: string, quality: VideoQuality): void;
172
+ /** Stop everyone's camera video (and your own camera); screen shares still come through. */
173
+ setAudioOnly(on: boolean): void;
174
+ /**
175
+ * Data saver for costly or weak mobile data: "off", "low", "minimal",
176
+ * "audio", or custom settings like `{ base: "low", activeSpeakerVideo: 2 }`.
177
+ */
178
+ setDataSaver(input: DataSaverInput): void;
179
+ /** Turn the audio-first fallback on or off; off while active brings video back now. */
180
+ setAudioFallback(enabled: boolean): void;
181
+ leave(reason?: string): void;
182
+ /** @internal */
183
+ _start(): Promise<void>;
184
+ }
185
+ /** Read (not verify) the claims in a join token. Works without atob/TextDecoder. */
186
+ export declare function decodeClaims(token: string): JoinClaims;