react-peer-chat 0.11.0 → 0.11.2

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,6 +1,6 @@
1
- import { useChat } from './chunk-FBLX5IM6.js';
2
- import { BiSolidMessageX, BiSolidMessageDetail, GrSend, BsFillMicFill, BsFillMicMuteFill } from './chunk-JJPIWKLG.js';
3
- import { __objRest, __spreadValues } from './chunk-LNEKYYG7.js';
1
+ import { useChat } from './chunk-CIIM7EHX.js';
2
+ import { BiSolidMessageX, BiSolidMessageDetail, GrSend, BsFillMicFill, BsFillMicMuteFill } from './chunk-QIPTWGEX.js';
3
+ import { __objRest, __spreadValues } from './chunk-FZ4QVG4I.js';
4
4
  import React, { useRef, useState, useEffect } from 'react';
5
5
 
6
6
  // src/styles.css
@@ -1,5 +1,5 @@
1
1
  import { getStorage, setStorage } from './chunk-ZYFPSCFE.js';
2
- import { __spreadValues, __spreadProps } from './chunk-LNEKYYG7.js';
2
+ import { __spreadValues, __async, __spreadProps } from './chunk-FZ4QVG4I.js';
3
3
  import { useState, useRef, useMemo, useEffect } from 'react';
4
4
 
5
5
  // src/constants.ts
@@ -66,6 +66,7 @@ function useChat({
66
66
  const [audio, setAudio] = useAudio(allowed);
67
67
  const connRef = useRef({});
68
68
  const callsRef = useRef({});
69
+ const localStreamRef = useRef(null);
69
70
  const audioContextRef = useRef(null);
70
71
  const mixerRef = useRef(null);
71
72
  const sourceNodesRef = useRef({});
@@ -75,8 +76,53 @@ function useChat({
75
76
  const remotePeerIds = Array.isArray(remotePeerId) ? remotePeerId : [remotePeerId];
76
77
  return { completePeerId: addPrefix(peerId), completeRemotePeerIds: remotePeerIds.map(addPrefix) };
77
78
  }, [peerId]);
79
+ function resetConnections(type = "all") {
80
+ switch (type) {
81
+ case "all":
82
+ resetConnections("data");
83
+ resetConnections("call");
84
+ break;
85
+ case "data":
86
+ Object.values(connRef.current).forEach(closeConnection);
87
+ connRef.current = {};
88
+ break;
89
+ case "call":
90
+ Object.values(callsRef.current).forEach(closeConnection);
91
+ Object.keys(sourceNodesRef.current).forEach(removePeerAudio);
92
+ callsRef.current = {};
93
+ break;
94
+ }
95
+ }
96
+ function handleConnection(conn) {
97
+ const peerId2 = conn.peer;
98
+ if (connRef.current[peerId2]) return conn.close();
99
+ conn.on("open", () => {
100
+ connRef.current[peerId2] = conn;
101
+ conn.on("data", ({ type, message, messages: messages2, remotePeerName }) => {
102
+ switch (type) {
103
+ case "init":
104
+ setRemotePeers((prev) => __spreadProps(__spreadValues({}, prev), { [peerId2]: remotePeerName }));
105
+ if (recoverChat) setMessages((old) => messages2.length > old.length ? messages2 : old);
106
+ break;
107
+ case "message":
108
+ receiveMessage(message);
109
+ break;
110
+ }
111
+ });
112
+ conn.send({ type: "init", remotePeerName: name, messages });
113
+ });
114
+ conn.on("close", () => {
115
+ conn.removeAllListeners();
116
+ delete connRef.current[peerId2];
117
+ });
118
+ }
78
119
  function handleCall(call) {
79
120
  const peerId2 = call.peer;
121
+ if (callsRef.current[peerId2]) return call.close();
122
+ if (!call.localStream) {
123
+ if (!localStreamRef.current) return call.close();
124
+ call.answer(localStreamRef.current);
125
+ }
80
126
  call.on("stream", () => {
81
127
  callsRef.current[peerId2] = call;
82
128
  if (!audioContextRef.current) audioContextRef.current = new AudioContext();
@@ -100,31 +146,14 @@ function useChat({
100
146
  delete callsRef.current[peerId2];
101
147
  });
102
148
  }
103
- function handleConnection(conn) {
104
- connRef.current[conn.peer] = conn;
105
- conn.on("open", () => {
106
- conn.on("data", ({ message, messages: messages2, remotePeerName, type }) => {
107
- if (type === "message") receiveMessage(message);
108
- else if (type === "init") {
109
- setRemotePeers((prev) => __spreadProps(__spreadValues({}, prev), { [conn.peer]: remotePeerName }));
110
- if (recoverChat) setMessages((old) => messages2.length > old.length ? messages2 : old);
111
- }
112
- });
113
- conn.send({ type: "init", remotePeerName: name, messages });
114
- });
115
- conn.on("close", conn.removeAllListeners);
116
- }
117
- function handleMediaError() {
118
- setAudio(false);
119
- onError(new Error("Microphone not accessible!"));
120
- }
121
149
  function receiveMessage(message) {
122
150
  addMessage(message);
123
151
  onMessageReceived == null ? void 0 : onMessageReceived(message);
124
152
  }
125
153
  function removePeerAudio(peerId2) {
126
- if (!sourceNodesRef.current[peerId2]) return;
127
- sourceNodesRef.current[peerId2].disconnect();
154
+ const source = sourceNodesRef.current[peerId2];
155
+ if (!source) return;
156
+ source.disconnect();
128
157
  delete sourceNodesRef.current[peerId2];
129
158
  }
130
159
  function sendMessage(message) {
@@ -135,6 +164,7 @@ function useChat({
135
164
  }
136
165
  useEffect(() => {
137
166
  if (!text && !audio) return;
167
+ let destroyed = false;
138
168
  import('peerjs').then(
139
169
  ({
140
170
  Peer,
@@ -145,20 +175,26 @@ function useChat({
145
175
  if (!data || !audioVideo) return onError(new Error("Browser not supported! Try some other browser."));
146
176
  const peer2 = new Peer(completePeerId, __spreadValues({ config: defaultConfig }, peerOptions));
147
177
  peer2.on("connection", handleConnection);
148
- peer2.on("disconnected", () => peer2.reconnect());
178
+ peer2.on("call", handleCall);
179
+ peer2.on("disconnected", () => {
180
+ resetConnections();
181
+ peer2.reconnect();
182
+ });
149
183
  peer2.on("error", (error) => {
150
184
  if (error.type === "network" || error.type === "server-error") {
185
+ resetConnections();
151
186
  setTimeout(() => peer2.reconnect(), 1e3);
152
187
  onNetworkError == null ? void 0 : onNetworkError(error);
153
188
  }
154
189
  onPeerError(error);
155
190
  });
156
- setPeer(peer2);
191
+ if (destroyed) peer2.destroy();
192
+ else setPeer(peer2);
157
193
  }
158
194
  );
159
195
  return () => {
196
+ destroyed = true;
160
197
  setPeer((prev) => {
161
- prev == null ? void 0 : prev.removeAllListeners();
162
198
  prev == null ? void 0 : prev.destroy();
163
199
  return void 0;
164
200
  });
@@ -166,52 +202,34 @@ function useChat({
166
202
  }, [completePeerId]);
167
203
  useEffect(() => {
168
204
  if (!text || !peer) return;
169
- const handleOpen = () => completeRemotePeerIds.forEach((id) => handleConnection(peer.connect(id)));
170
- if (peer.open) handleOpen();
171
- peer.on("open", handleOpen);
205
+ const connectData = () => completeRemotePeerIds.forEach((id) => handleConnection(peer.connect(id)));
206
+ if (peer.open) connectData();
207
+ peer.on("open", connectData);
172
208
  return () => {
173
- peer.off("open", handleOpen);
174
- Object.values(connRef.current).forEach(closeConnection);
175
- connRef.current = {};
209
+ peer.off("open", connectData);
210
+ resetConnections("data");
176
211
  };
177
212
  }, [text, peer]);
178
213
  useEffect(() => {
179
214
  if (!audio || !peer) return;
180
- let localStream;
181
- const setupAudio = () => {
182
- if (!navigator.mediaDevices) return handleMediaError();
183
- navigator.mediaDevices.getUserMedia({
184
- video: false,
185
- audio: {
186
- autoGainControl: true,
187
- noiseSuppression: true,
188
- echoCancellation: true
189
- }
190
- }).then((stream) => {
191
- localStream = stream;
192
- completeRemotePeerIds.forEach((id) => {
193
- if (callsRef.current[id]) return;
194
- const call = peer.call(id, stream);
195
- handleCall(call);
196
- });
197
- peer.on("call", (call) => {
198
- if (callsRef.current[call.peer]) return call.close();
199
- call.answer(stream);
200
- handleCall(call);
201
- });
202
- }).catch(handleMediaError);
203
- };
215
+ const setupAudio = () => __async(null, null, function* () {
216
+ try {
217
+ localStreamRef.current = yield navigator.mediaDevices.getUserMedia({ video: false, audio: { autoGainControl: true, noiseSuppression: true, echoCancellation: true } });
218
+ completeRemotePeerIds.forEach((id) => localStreamRef.current && handleCall(peer.call(id, localStreamRef.current)));
219
+ } catch (e) {
220
+ setAudio(false);
221
+ onError(new Error("Microphone not accessible"));
222
+ }
223
+ });
204
224
  if (peer.open) setupAudio();
205
225
  peer.on("open", setupAudio);
206
226
  return () => {
207
- var _a;
227
+ var _a, _b;
208
228
  peer.off("open", setupAudio);
209
- peer.off("call");
210
- localStream == null ? void 0 : localStream.getTracks().forEach((track) => track.stop());
211
- Object.values(callsRef.current).forEach(closeConnection);
212
- callsRef.current = {};
213
- Object.keys(sourceNodesRef.current).forEach(removePeerAudio);
214
- (_a = audioContextRef.current) == null ? void 0 : _a.close();
229
+ (_a = localStreamRef.current) == null ? void 0 : _a.getTracks().forEach((track) => track.stop());
230
+ resetConnections("call");
231
+ (_b = audioContextRef.current) == null ? void 0 : _b.close();
232
+ localStreamRef.current = null;
215
233
  audioContextRef.current = null;
216
234
  mixerRef.current = null;
217
235
  };
@@ -224,10 +242,7 @@ function useMessages() {
224
242
  return [messages, setMessages, addMessage];
225
243
  }
226
244
  function useStorage(key, initialValue, local = false) {
227
- const [storedValue, setStoredValue] = useState(() => {
228
- if (typeof window === "undefined") return initialValue;
229
- return getStorage(key, initialValue, local);
230
- });
245
+ const [storedValue, setStoredValue] = useState(() => typeof window === "undefined" ? initialValue : getStorage(key, initialValue, local));
231
246
  const setValue = (value) => {
232
247
  setStoredValue((prev) => {
233
248
  const next = isSetStateFunction(value) ? value(prev) : value;
@@ -29,5 +29,25 @@ var __objRest = (source, exclude) => {
29
29
  }
30
30
  return target;
31
31
  };
32
+ var __async = (__this, __arguments, generator) => {
33
+ return new Promise((resolve, reject) => {
34
+ var fulfilled = (value) => {
35
+ try {
36
+ step(generator.next(value));
37
+ } catch (e) {
38
+ reject(e);
39
+ }
40
+ };
41
+ var rejected = (value) => {
42
+ try {
43
+ step(generator.throw(value));
44
+ } catch (e) {
45
+ reject(e);
46
+ }
47
+ };
48
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
49
+ step((generator = generator.apply(__this, __arguments)).next());
50
+ });
51
+ };
32
52
 
33
- export { __objRest, __spreadProps, __spreadValues };
53
+ export { __async, __objRest, __spreadProps, __spreadValues };
@@ -1,4 +1,4 @@
1
- import { __spreadValues } from './chunk-LNEKYYG7.js';
1
+ import { __spreadValues } from './chunk-FZ4QVG4I.js';
2
2
  import React from 'react';
3
3
 
4
4
  function BiSolidMessageDetail(props) {
@@ -1,5 +1,5 @@
1
- export { Chat as default } from './chunks/chunk-6JONVNJK.js';
2
- import './chunks/chunk-FBLX5IM6.js';
3
- import './chunks/chunk-JJPIWKLG.js';
1
+ export { Chat as default } from './chunks/chunk-B2RQAOIC.js';
2
+ import './chunks/chunk-CIIM7EHX.js';
3
+ import './chunks/chunk-QIPTWGEX.js';
4
4
  import './chunks/chunk-ZYFPSCFE.js';
5
- import './chunks/chunk-LNEKYYG7.js';
5
+ import './chunks/chunk-FZ4QVG4I.js';
package/dist/hooks.js CHANGED
@@ -1,3 +1,3 @@
1
- export { useAudio, useChat, useMessages, useStorage } from './chunks/chunk-FBLX5IM6.js';
1
+ export { useAudio, useChat, useMessages, useStorage } from './chunks/chunk-CIIM7EHX.js';
2
2
  import './chunks/chunk-ZYFPSCFE.js';
3
- import './chunks/chunk-LNEKYYG7.js';
3
+ import './chunks/chunk-FZ4QVG4I.js';
package/dist/icons.js CHANGED
@@ -1,2 +1,2 @@
1
- export { BiSolidMessageDetail, BiSolidMessageX, BsFillMicFill, BsFillMicMuteFill, GrSend } from './chunks/chunk-JJPIWKLG.js';
2
- import './chunks/chunk-LNEKYYG7.js';
1
+ export { BiSolidMessageDetail, BiSolidMessageX, BsFillMicFill, BsFillMicMuteFill, GrSend } from './chunks/chunk-QIPTWGEX.js';
2
+ import './chunks/chunk-FZ4QVG4I.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { Chat as default } from './chunks/chunk-6JONVNJK.js';
2
- export { useChat } from './chunks/chunk-FBLX5IM6.js';
3
- import './chunks/chunk-JJPIWKLG.js';
1
+ export { Chat as default } from './chunks/chunk-B2RQAOIC.js';
2
+ export { useChat } from './chunks/chunk-CIIM7EHX.js';
3
+ import './chunks/chunk-QIPTWGEX.js';
4
4
  export { clearChat } from './chunks/chunk-ZYFPSCFE.js';
5
- import './chunks/chunk-LNEKYYG7.js';
5
+ import './chunks/chunk-FZ4QVG4I.js';
@@ -1,2 +1,2 @@
1
1
  export { clearChat, getStorage, removeStorage, setStorage } from '../chunks/chunk-ZYFPSCFE.js';
2
- import '../chunks/chunk-LNEKYYG7.js';
2
+ import '../chunks/chunk-FZ4QVG4I.js';
package/dist/types.d.ts CHANGED
@@ -15,6 +15,7 @@ type MessageEventHandler = (message: Message) => void;
15
15
  type PeerErrorHandler = ErrorHandler<PeerError<`${PeerErrorType}`>>;
16
16
 
17
17
  type RemotePeerId = string | string[];
18
+ type ResetConnectionType = "all" | "data" | "call";
18
19
  type UseChatProps = {
19
20
  peerId: string;
20
21
  name?: string;
@@ -54,4 +55,4 @@ type DialogPosition = "left" | "center" | "right";
54
55
  type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
55
56
  type RemotePeers = Record<string, string>;
56
57
 
57
- export type { ChatProps, Children, ChildrenOptions, Connection, DialogOptions, DialogPosition, DivProps, ErrorHandler, IconProps, InputMessage, Message, MessageEventHandler, PeerErrorHandler, RemotePeerId, RemotePeers, UseChatProps, UseChatReturn };
58
+ export type { ChatProps, Children, ChildrenOptions, Connection, DialogOptions, DialogPosition, DivProps, ErrorHandler, IconProps, InputMessage, Message, MessageEventHandler, PeerErrorHandler, RemotePeerId, RemotePeers, ResetConnectionType, UseChatProps, UseChatReturn };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-peer-chat",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "An easy to use react component for impleting peer-to-peer chatting.",
5
5
  "license": "MIT",
6
6
  "author": "Sahil Aggarwal <aggarwalsahil2004@gmail.com>",
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@release-it/conventional-changelog": "^10.0.4",
39
- "@types/react": "^19.2.7",
39
+ "@types/react": "^19.2.8",
40
40
  "prettier-package-json": "^2.8.0",
41
- "release-it": "^19.2.2",
41
+ "release-it": "^19.2.3",
42
42
  "tsup": "^8.5.1",
43
43
  "typescript": "^5.9.3"
44
44
  },