react-peer-chat 0.11.10 → 0.12.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.
@@ -1,310 +0,0 @@
1
- import { getStorage, subscribeToStorage, setStorage } from './chunk-MRYWIJDZ.js';
2
- import { __spreadValues, __async, __spreadProps } from './chunk-FZ4QVG4I.js';
3
- import { useState, useRef, useMemo, useEffect } from 'react';
4
-
5
- // src/constants.ts
6
- var turnAccounts = [
7
- { username: "70061a377b51f3a3d01c11e3", credential: "lHV4NYJ5Rfl5JNa9" },
8
- { username: "13b19eb65bbf6e9f96d64b72", credential: "7R9P/+7y7Q516Etv" },
9
- { username: "3469603f5cdc7ca4a1e891ae", credential: "/jMyLSDbbcgqpVQv" },
10
- { username: "a7926f4dcc4a688d41f89752", credential: "ZYM8jFYeb8bQkL+N" },
11
- { username: "0be25ab7f61d9d733ba94809", credential: "hiiSwWVch+ftt3SX" },
12
- { username: "3c25ba948daeab04f9b66187", credential: "FQB3GQwd27Y0dPeK" }
13
- ];
14
- var defaults = {
15
- config: {
16
- iceServers: [
17
- {
18
- urls: ["stun:stun.l.google.com:19302", "stun:stun.relay.metered.ca:80"]
19
- }
20
- ].concat(
21
- turnAccounts.map((account) => __spreadValues({
22
- urls: [
23
- "turn:standard.relay.metered.ca:80",
24
- "turn:standard.relay.metered.ca:80?transport=tcp",
25
- "turn:standard.relay.metered.ca:443",
26
- "turns:standard.relay.metered.ca:443?transport=tcp"
27
- ]
28
- }, account))
29
- )
30
- },
31
- peerOptions: {},
32
- remotePeerId: []
33
- };
34
- var iosRegex = /iPhone|iPad|iPod/i;
35
- var mobileRegex = /Android|webOS|BlackBerry|IEMobile|Opera Mini/i;
36
-
37
- // src/lib/connection.ts
38
- function closeConnection(conn) {
39
- conn.removeAllListeners();
40
- conn.close();
41
- }
42
-
43
- // src/lib/utils.ts
44
- var addPrefix = (str) => `rpc-${str}`;
45
- function isMobile(iOS = true) {
46
- var _a;
47
- let result = (_a = navigator.userAgentData) == null ? void 0 : _a.mobile;
48
- result != null ? result : result = mobileRegex.test(navigator.userAgent) || iOS && iosRegex.test(navigator.userAgent);
49
- return result;
50
- }
51
-
52
- // src/lib/react.ts
53
- function isSetStateFunction(v) {
54
- return typeof v === "function";
55
- }
56
-
57
- // src/hooks.ts
58
- var { config: defaultConfig, peerOptions: defaultPeerOptions, remotePeerId: defaultRemotePeerId } = defaults;
59
- function useChat({
60
- peerId,
61
- name = "Anonymous User",
62
- remotePeerId = defaultRemotePeerId,
63
- peerOptions = defaultPeerOptions,
64
- text = true,
65
- recoverChat = false,
66
- audio: allowed = true,
67
- onError = console.error,
68
- onPeerError = console.error,
69
- onNetworkError,
70
- onMessageSent,
71
- onMessageReceived
72
- }) {
73
- const [peerEpoch, setPeerEpoch] = useState(0);
74
- const [peerGeneration, setPeerGeneration] = useState(0);
75
- const [audio, setAudio] = useAudio(allowed);
76
- const peerRef = useRef(null);
77
- const scheduleReconnectRef = useRef(null);
78
- const connRef = useRef({});
79
- const callsRef = useRef({});
80
- const localStreamRef = useRef(null);
81
- const audioContextRef = useRef(null);
82
- const mixerRef = useRef(null);
83
- const sourceNodesRef = useRef({});
84
- const [messages, setMessages, addMessage] = useMessages();
85
- const [remotePeers, setRemotePeers] = useStorage("rpc-remote-peer", {});
86
- const { completePeerId, completeRemotePeerIds } = useMemo(() => {
87
- const remotePeerIds = Array.isArray(remotePeerId) ? remotePeerId : [remotePeerId];
88
- return { completePeerId: addPrefix(peerId), completeRemotePeerIds: remotePeerIds.map(addPrefix) };
89
- }, [peerId]);
90
- function resetConnections(type = "all") {
91
- switch (type) {
92
- case "all":
93
- resetConnections("data");
94
- resetConnections("call");
95
- break;
96
- case "data":
97
- Object.values(connRef.current).forEach(closeConnection);
98
- connRef.current = {};
99
- break;
100
- case "call":
101
- Object.values(callsRef.current).forEach(closeConnection);
102
- Object.keys(sourceNodesRef.current).forEach(removePeerAudio);
103
- callsRef.current = {};
104
- break;
105
- }
106
- }
107
- function handleConnection(conn) {
108
- const peerId2 = conn.peer;
109
- conn.on("open", () => {
110
- var _a;
111
- (_a = connRef.current[peerId2]) == null ? void 0 : _a.close();
112
- connRef.current[peerId2] = conn;
113
- conn.on("data", ({ type, message, messages: messages2, remotePeerName }) => {
114
- switch (type) {
115
- case "init":
116
- setRemotePeers((prev) => __spreadProps(__spreadValues({}, prev), { [peerId2]: remotePeerName }));
117
- if (recoverChat) setMessages((old) => messages2.length > old.length ? messages2 : old);
118
- break;
119
- case "message":
120
- receiveMessage(message);
121
- break;
122
- }
123
- });
124
- conn.send({ type: "init", remotePeerName: name, messages });
125
- });
126
- conn.on("close", () => {
127
- conn.removeAllListeners();
128
- if (connRef.current[peerId2] === conn) delete connRef.current[peerId2];
129
- });
130
- }
131
- function handleCall(call) {
132
- const peerId2 = call.peer;
133
- if (!call.localStream) {
134
- if (!localStreamRef.current) return call.close();
135
- call.answer(localStreamRef.current);
136
- }
137
- call.on("stream", () => {
138
- var _a;
139
- (_a = callsRef.current[peerId2]) == null ? void 0 : _a.close();
140
- callsRef.current[peerId2] = call;
141
- if (!audioContextRef.current) audioContextRef.current = new AudioContext();
142
- if (audioContextRef.current.state === "suspended") audioContextRef.current.resume();
143
- if (!mixerRef.current) {
144
- mixerRef.current = audioContextRef.current.createGain();
145
- mixerRef.current.connect(audioContextRef.current.destination);
146
- }
147
- removePeerAudio(peerId2);
148
- const audio2 = new Audio();
149
- audio2.srcObject = call.remoteStream;
150
- audio2.autoplay = true;
151
- audio2.muted = false;
152
- const source = audioContextRef.current.createMediaElementSource(audio2);
153
- source.connect(mixerRef.current);
154
- sourceNodesRef.current[peerId2] = source;
155
- });
156
- call.on("close", () => {
157
- call.removeAllListeners();
158
- if (callsRef.current[peerId2] === call) {
159
- removePeerAudio(peerId2);
160
- delete callsRef.current[peerId2];
161
- }
162
- });
163
- }
164
- function receiveMessage(message) {
165
- addMessage(message);
166
- onMessageReceived == null ? void 0 : onMessageReceived(message);
167
- }
168
- function removePeerAudio(peerId2) {
169
- const source = sourceNodesRef.current[peerId2];
170
- if (!source) return;
171
- source.disconnect();
172
- delete sourceNodesRef.current[peerId2];
173
- }
174
- function sendMessage(message) {
175
- const event = { type: "message", message: __spreadProps(__spreadValues({}, message), { name }) };
176
- addMessage(event.message);
177
- Object.values(connRef.current).forEach((conn) => conn.send(event));
178
- onMessageSent == null ? void 0 : onMessageSent(event.message);
179
- }
180
- useEffect(() => {
181
- const onOnline = () => {
182
- var _a, _b;
183
- return ((_a = peerRef.current) == null ? void 0 : _a.disconnected) && ((_b = scheduleReconnectRef.current) == null ? void 0 : _b.call(scheduleReconnectRef));
184
- };
185
- window.addEventListener("online", onOnline);
186
- return () => window.removeEventListener("online", onOnline);
187
- }, []);
188
- useEffect(() => {
189
- if (!text && !audio) return;
190
- let destroyed = false;
191
- let reconnecting = false;
192
- let reconnectTimer;
193
- scheduleReconnectRef.current = () => {
194
- if (destroyed || reconnecting) return;
195
- reconnecting = true;
196
- reconnectTimer = setTimeout(() => {
197
- const peer = peerRef.current;
198
- if (peer) {
199
- if (isMobile()) setPeerGeneration((prev) => prev + 1);
200
- else peer.reconnect();
201
- }
202
- reconnecting = false;
203
- }, 1e3);
204
- };
205
- const scheduleReconnect = scheduleReconnectRef.current;
206
- import('peerjs').then(
207
- ({
208
- Peer,
209
- util: {
210
- supports: { audioVideo, data }
211
- }
212
- }) => {
213
- if (destroyed) return;
214
- if (!data || !audioVideo) return onError(new Error("Browser not supported! Try some other browser."));
215
- peerRef.current = new Peer(completePeerId, __spreadValues({ config: defaultConfig }, peerOptions));
216
- setPeerEpoch((prev) => prev + 1);
217
- const peer = peerRef.current;
218
- peer.on("connection", handleConnection);
219
- peer.on("call", handleCall);
220
- peer.on("disconnected", () => {
221
- resetConnections();
222
- scheduleReconnect();
223
- });
224
- peer.on("error", (error) => {
225
- if (error.type === "network" || error.type === "server-error") {
226
- resetConnections();
227
- scheduleReconnect();
228
- onNetworkError == null ? void 0 : onNetworkError(error);
229
- }
230
- onPeerError(error);
231
- });
232
- }
233
- );
234
- return () => {
235
- var _a, _b;
236
- destroyed = true;
237
- reconnecting = false;
238
- clearTimeout(reconnectTimer);
239
- (_a = peerRef.current) == null ? void 0 : _a.removeAllListeners();
240
- (_b = peerRef.current) == null ? void 0 : _b.destroy();
241
- peerRef.current = null;
242
- };
243
- }, [completePeerId, peerGeneration]);
244
- useEffect(() => {
245
- if (!text) return;
246
- const peer = peerRef.current;
247
- if (!peer) return;
248
- const connectData = () => completeRemotePeerIds.forEach((id) => handleConnection(peer.connect(id)));
249
- if (peer.open) connectData();
250
- peer.on("open", connectData);
251
- return () => {
252
- peer.off("open", connectData);
253
- resetConnections("data");
254
- };
255
- }, [text, peerEpoch]);
256
- useEffect(() => {
257
- if (!audio) return;
258
- const peer = peerRef.current;
259
- if (!peer) return;
260
- const setupAudio = () => __async(null, null, function* () {
261
- try {
262
- if (!localStreamRef.current)
263
- localStreamRef.current = yield navigator.mediaDevices.getUserMedia({ video: false, audio: { autoGainControl: true, noiseSuppression: true, echoCancellation: true } });
264
- completeRemotePeerIds.forEach((id) => localStreamRef.current && handleCall(peer.call(id, localStreamRef.current)));
265
- } catch (e) {
266
- setAudio(false);
267
- onError(new Error("Microphone not accessible"));
268
- }
269
- });
270
- if (peer.open) setupAudio();
271
- peer.on("open", setupAudio);
272
- return () => {
273
- var _a, _b;
274
- peer.off("open", setupAudio);
275
- (_a = localStreamRef.current) == null ? void 0 : _a.getTracks().forEach((track) => track.stop());
276
- resetConnections("call");
277
- (_b = audioContextRef.current) == null ? void 0 : _b.close();
278
- localStreamRef.current = null;
279
- audioContextRef.current = null;
280
- mixerRef.current = null;
281
- };
282
- }, [audio, peerEpoch]);
283
- return { peerId: completePeerId, remotePeers, messages, sendMessage, audio, setAudio };
284
- }
285
- function useMessages() {
286
- const [messages, setMessages] = useStorage("rpc-messages", []);
287
- const addMessage = (message) => setMessages((prev) => prev.concat(message));
288
- return [messages, setMessages, addMessage];
289
- }
290
- function useStorage(key, initialValue, local = false) {
291
- const [storedValue, setStoredValue] = useState(() => typeof window === "undefined" ? initialValue : getStorage(key, local, initialValue));
292
- const setValue = (value) => {
293
- setStoredValue((prev) => {
294
- const next = isSetStateFunction(value) ? value(prev) : value;
295
- setStorage(key, next, local);
296
- return next;
297
- });
298
- };
299
- useEffect(() => {
300
- return subscribeToStorage(key, local, (value) => setStoredValue(value != null ? value : initialValue));
301
- }, [key, local]);
302
- return [storedValue, setValue];
303
- }
304
- function useAudio(allowed) {
305
- const [audio, setAudio] = useStorage("rpc-audio", false, true);
306
- const enabled = audio && allowed;
307
- return [enabled, setAudio];
308
- }
309
-
310
- export { useAudio, useChat, useMessages, useStorage };
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- import { ChatProps } from './types.js';
3
- import 'peerjs';
4
-
5
- declare function Chat({ text, audio, onMessageReceived, dialogOptions, props, children, ...hookProps }: ChatProps): React.JSX.Element;
6
-
7
- export { Chat as default };
@@ -1,5 +0,0 @@
1
- export { Chat as default } from './chunks/chunk-6FW6VHDM.js';
2
- import './chunks/chunk-R74TCSLB.js';
3
- import './chunks/chunk-QIPTWGEX.js';
4
- import './chunks/chunk-MRYWIJDZ.js';
5
- import './chunks/chunk-FZ4QVG4I.js';
package/dist/hooks.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import { SetStateAction } from 'react';
2
- import { UseChatProps, UseChatReturn, Message } from './types.js';
3
- import 'peerjs';
4
-
5
- declare function useChat({ peerId, name, remotePeerId, peerOptions, text, recoverChat, audio: allowed, onError, onPeerError, onNetworkError, onMessageSent, onMessageReceived, }: UseChatProps): UseChatReturn;
6
- declare function useMessages(): readonly [Message[], (value: SetStateAction<Message[]>) => void, (message: Message) => void];
7
- declare function useStorage<T>(key: string, initialValue: T, local?: boolean): readonly [T, (value: SetStateAction<T>) => void];
8
- declare function useStorage<T>(key: string, initialValue?: T, local?: boolean): readonly [T | undefined, (value: SetStateAction<T | undefined>) => void];
9
- declare function useAudio(allowed: boolean): readonly [boolean, (value: SetStateAction<boolean>) => void];
10
-
11
- export { useAudio, useChat, useMessages, useStorage };
package/dist/hooks.js DELETED
@@ -1,3 +0,0 @@
1
- export { useAudio, useChat, useMessages, useStorage } from './chunks/chunk-R74TCSLB.js';
2
- import './chunks/chunk-MRYWIJDZ.js';
3
- import './chunks/chunk-FZ4QVG4I.js';
package/dist/icons.js DELETED
@@ -1,2 +0,0 @@
1
- export { BiSolidMessageDetail, BiSolidMessageX, BsFillMicFill, BsFillMicMuteFill, GrSend } from './chunks/chunk-QIPTWGEX.js';
2
- import './chunks/chunk-FZ4QVG4I.js';
package/dist/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- export { default } from './components.js';
2
- export { useChat } from './hooks.js';
3
- export { clearChat } from './lib/storage.js';
4
- import 'react';
5
- import './types.js';
6
- import 'peerjs';
package/dist/index.js DELETED
@@ -1,5 +0,0 @@
1
- export { Chat as default } from './chunks/chunk-6FW6VHDM.js';
2
- export { useChat } from './chunks/chunk-R74TCSLB.js';
3
- import './chunks/chunk-QIPTWGEX.js';
4
- export { clearChat } from './chunks/chunk-MRYWIJDZ.js';
5
- import './chunks/chunk-FZ4QVG4I.js';
@@ -1,11 +0,0 @@
1
- import { VoidFunction } from '../types.js';
2
- import 'peerjs';
3
- import 'react';
4
-
5
- declare function clearChat(): void;
6
- declare function getStorage<T>(key: string, local: boolean, fallbackValue?: T): T | undefined;
7
- declare function removeStorage(key: string, local: boolean): void;
8
- declare function setStorage(key: string, value: unknown, local: boolean): void;
9
- declare function subscribeToStorage<T>(key: string, local: boolean, callback: (value: T) => void): VoidFunction;
10
-
11
- export { clearChat, getStorage, removeStorage, setStorage, subscribeToStorage };
@@ -1,2 +0,0 @@
1
- export { clearChat, getStorage, removeStorage, setStorage, subscribeToStorage } from '../chunks/chunk-MRYWIJDZ.js';
2
- import '../chunks/chunk-FZ4QVG4I.js';
package/dist/types.d.ts DELETED
@@ -1,59 +0,0 @@
1
- import { PeerOptions, PeerError, PeerErrorType, DataConnection, MediaConnection } from 'peerjs';
2
- export { PeerOptions } from 'peerjs';
3
- import { CSSProperties, DetailedHTMLProps, HTMLAttributes, SetStateAction, ReactNode } from 'react';
4
-
5
- type Connection = DataConnection | MediaConnection;
6
- type ChildrenOptions = {
7
- remotePeers: RemotePeers;
8
- messages: Message[];
9
- sendMessage: (message: InputMessage) => void;
10
- audio: boolean;
11
- setAudio: (value: SetStateAction<boolean>) => void;
12
- };
13
- type ErrorHandler<E = Error> = (error: E) => void;
14
- type InputMessage = {
15
- id: string;
16
- text: string;
17
- };
18
- type Message = InputMessage & {
19
- name: string;
20
- };
21
- type MessageEventHandler = (message: Message) => void;
22
- type PeerErrorHandler = ErrorHandler<PeerError<`${PeerErrorType}`>>;
23
-
24
- type RemotePeerId = string | string[];
25
- type ResetConnectionType = "all" | "data" | "call";
26
- type UseChatProps = {
27
- peerId: string;
28
- name?: string;
29
- remotePeerId?: RemotePeerId;
30
- text?: boolean;
31
- recoverChat?: boolean;
32
- audio?: boolean;
33
- peerOptions?: PeerOptions;
34
- onError?: ErrorHandler;
35
- onPeerError?: PeerErrorHandler;
36
- onNetworkError?: PeerErrorHandler;
37
- onMessageSent?: MessageEventHandler;
38
- onMessageReceived?: MessageEventHandler;
39
- };
40
- type UseChatReturn = ChildrenOptions & {
41
- peerId: string;
42
- };
43
- type VoidFunction = () => void;
44
- type IconProps = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
45
- type ChatProps = UseChatProps & {
46
- dialogOptions?: DialogOptions;
47
- props?: DivProps;
48
- children?: Children;
49
- };
50
- type Children = (childrenOptions: ChildrenOptions) => ReactNode;
51
- type DialogOptions = {
52
- position?: DialogPosition;
53
- style?: CSSProperties;
54
- };
55
- type DialogPosition = "left" | "center" | "right";
56
- type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
57
- type RemotePeers = Record<string, string>;
58
-
59
- export type { ChatProps, Children, ChildrenOptions, Connection, DialogOptions, DialogPosition, DivProps, ErrorHandler, IconProps, InputMessage, Message, MessageEventHandler, PeerErrorHandler, RemotePeerId, RemotePeers, ResetConnectionType, UseChatProps, UseChatReturn, VoidFunction };
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
-