react-peer-chat 0.11.0 → 0.11.1

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,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
@@ -75,8 +75,49 @@ function useChat({
75
75
  const remotePeerIds = Array.isArray(remotePeerId) ? remotePeerId : [remotePeerId];
76
76
  return { completePeerId: addPrefix(peerId), completeRemotePeerIds: remotePeerIds.map(addPrefix) };
77
77
  }, [peerId]);
78
+ function resetConnections(type = "all") {
79
+ switch (type) {
80
+ case "all":
81
+ resetConnections("data");
82
+ resetConnections("call");
83
+ break;
84
+ case "data":
85
+ Object.values(connRef.current).forEach(closeConnection);
86
+ connRef.current = {};
87
+ break;
88
+ case "call":
89
+ Object.values(callsRef.current).forEach(closeConnection);
90
+ Object.keys(sourceNodesRef.current).forEach(removePeerAudio);
91
+ callsRef.current = {};
92
+ break;
93
+ }
94
+ }
95
+ function handleConnection(conn) {
96
+ const peerId2 = conn.peer;
97
+ if (connRef.current[peerId2]) return conn.close();
98
+ connRef.current[peerId2] = conn;
99
+ conn.on("open", () => {
100
+ conn.on("data", ({ type, message, messages: messages2, remotePeerName }) => {
101
+ switch (type) {
102
+ case "init":
103
+ setRemotePeers((prev) => __spreadProps(__spreadValues({}, prev), { [peerId2]: remotePeerName }));
104
+ if (recoverChat) setMessages((old) => messages2.length > old.length ? messages2 : old);
105
+ break;
106
+ case "message":
107
+ receiveMessage(message);
108
+ break;
109
+ }
110
+ });
111
+ conn.send({ type: "init", remotePeerName: name, messages });
112
+ });
113
+ conn.on("close", () => {
114
+ conn.removeAllListeners();
115
+ delete connRef.current[peerId2];
116
+ });
117
+ }
78
118
  function handleCall(call) {
79
119
  const peerId2 = call.peer;
120
+ if (callsRef.current[peerId2]) return call.close();
80
121
  call.on("stream", () => {
81
122
  callsRef.current[peerId2] = call;
82
123
  if (!audioContextRef.current) audioContextRef.current = new AudioContext();
@@ -100,31 +141,14 @@ function useChat({
100
141
  delete callsRef.current[peerId2];
101
142
  });
102
143
  }
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
144
  function receiveMessage(message) {
122
145
  addMessage(message);
123
146
  onMessageReceived == null ? void 0 : onMessageReceived(message);
124
147
  }
125
148
  function removePeerAudio(peerId2) {
126
- if (!sourceNodesRef.current[peerId2]) return;
127
- sourceNodesRef.current[peerId2].disconnect();
149
+ const source = sourceNodesRef.current[peerId2];
150
+ if (!source) return;
151
+ source.disconnect();
128
152
  delete sourceNodesRef.current[peerId2];
129
153
  }
130
154
  function sendMessage(message) {
@@ -135,6 +159,7 @@ function useChat({
135
159
  }
136
160
  useEffect(() => {
137
161
  if (!text && !audio) return;
162
+ let destroyed = false;
138
163
  import('peerjs').then(
139
164
  ({
140
165
  Peer,
@@ -145,20 +170,26 @@ function useChat({
145
170
  if (!data || !audioVideo) return onError(new Error("Browser not supported! Try some other browser."));
146
171
  const peer2 = new Peer(completePeerId, __spreadValues({ config: defaultConfig }, peerOptions));
147
172
  peer2.on("connection", handleConnection);
148
- peer2.on("disconnected", () => peer2.reconnect());
173
+ peer2.on("call", handleCall);
174
+ peer2.on("disconnected", () => {
175
+ resetConnections();
176
+ peer2.reconnect();
177
+ });
149
178
  peer2.on("error", (error) => {
150
179
  if (error.type === "network" || error.type === "server-error") {
180
+ resetConnections();
151
181
  setTimeout(() => peer2.reconnect(), 1e3);
152
182
  onNetworkError == null ? void 0 : onNetworkError(error);
153
183
  }
154
184
  onPeerError(error);
155
185
  });
156
- setPeer(peer2);
186
+ if (destroyed) peer2.destroy();
187
+ else setPeer(peer2);
157
188
  }
158
189
  );
159
190
  return () => {
191
+ destroyed = true;
160
192
  setPeer((prev) => {
161
- prev == null ? void 0 : prev.removeAllListeners();
162
193
  prev == null ? void 0 : prev.destroy();
163
194
  return void 0;
164
195
  });
@@ -166,51 +197,35 @@ function useChat({
166
197
  }, [completePeerId]);
167
198
  useEffect(() => {
168
199
  if (!text || !peer) return;
169
- const handleOpen = () => completeRemotePeerIds.forEach((id) => handleConnection(peer.connect(id)));
170
- if (peer.open) handleOpen();
171
- peer.on("open", handleOpen);
200
+ const connectData = () => completeRemotePeerIds.forEach((id) => handleConnection(peer.connect(id)));
201
+ if (peer.open) connectData();
202
+ peer.on("open", connectData);
172
203
  return () => {
173
- peer.off("open", handleOpen);
174
- Object.values(connRef.current).forEach(closeConnection);
175
- connRef.current = {};
204
+ peer.off("open", connectData);
205
+ resetConnections("data");
176
206
  };
177
207
  }, [text, peer]);
178
208
  useEffect(() => {
179
209
  if (!audio || !peer) return;
180
210
  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;
211
+ const setupAudio = () => __async(null, null, function* () {
212
+ try {
213
+ localStream = yield navigator.mediaDevices.getUserMedia({ video: false, audio: { autoGainControl: true, noiseSuppression: true, echoCancellation: true } });
192
214
  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);
215
+ if (!callsRef.current[id]) handleCall(peer.call(id, localStream));
201
216
  });
202
- }).catch(handleMediaError);
203
- };
217
+ } catch (e) {
218
+ setAudio(false);
219
+ onError(new Error("Microphone not accessible"));
220
+ }
221
+ });
204
222
  if (peer.open) setupAudio();
205
223
  peer.on("open", setupAudio);
206
224
  return () => {
207
225
  var _a;
208
226
  peer.off("open", setupAudio);
209
- peer.off("call");
210
227
  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);
228
+ resetConnections("call");
214
229
  (_a = audioContextRef.current) == null ? void 0 : _a.close();
215
230
  audioContextRef.current = null;
216
231
  mixerRef.current = null;
@@ -224,10 +239,7 @@ function useMessages() {
224
239
  return [messages, setMessages, addMessage];
225
240
  }
226
241
  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
- });
242
+ const [storedValue, setStoredValue] = useState(() => typeof window === "undefined" ? initialValue : getStorage(key, initialValue, local));
231
243
  const setValue = (value) => {
232
244
  setStoredValue((prev) => {
233
245
  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,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-B2B7BBRE.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
- 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-YQPRV5JQ.js';
2
+ import './chunks/chunk-B2B7BBRE.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-B2B7BBRE.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-YQPRV5JQ.js';
2
+ export { useChat } from './chunks/chunk-B2B7BBRE.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.1",
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
  },