@poolse/react 2.28.0 → 3.0.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/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to `@poolse/react` are documented here. Format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [semver](https://semver.org).
6
6
 
7
+
8
+ ## [3.0.0] — 2026-10-26
9
+
10
+ ### Changed
11
+
12
+ - **License.** From 3.0.0 this package is under the poolse SDK License
13
+ (see `LICENSE`): free to use, including commercially, in apps built on
14
+ poolse; not for use with other backends or to build a competing
15
+ service. Versions before 3.0.0 remain MIT.
16
+ - First stable release; all `@poolse/*` packages move to 3.0.0 together.
17
+ Earlier versions are deprecated. See `MIGRATING.md`.
18
+
19
+ ## [2.29.0] — 2026-10-22
20
+
21
+ ### Removed
22
+
23
+ - **`useCalls` and `useVoiceRoom`** — the legacy socket-ringing calls and
24
+ the peer-to-peer voice room, both retired on the server. Use `useRoom`
25
+ (rooms, opt-in ringing) and `useLiveCall` on the web; phones use
26
+ `@poolse/react-native-calls`.
27
+
7
28
  ## [2.24.0] — 2026-10-14
8
29
 
9
30
  ### Fixed
package/LICENSE CHANGED
@@ -1,21 +1,206 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Poolse
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.
1
+ poolse SDK License
2
+
3
+ Copyright (c) 2026 Torsten Labs DOO. All rights reserved.
4
+
5
+ Version 1.0. Applies to poolse SDK releases from version 3.0.0 onwards.
6
+
7
+
8
+ SUMMARY (NOT PART OF THE LICENSE TERMS)
9
+
10
+ This summary is for convenience only. It is not part of the license and
11
+ has no legal effect. If it differs from the terms below, the terms below
12
+ apply.
13
+
14
+ - You can use, copy and modify the SDK for free, including in
15
+ commercial apps, as long as your app talks to the poolse Services.
16
+ - You can ship the SDK inside your app, compiled or bundled, including
17
+ the native iOS and Android source code needed to build it.
18
+ - You cannot use the SDK with any other backend, use it to build a
19
+ competing chat, realtime, calling or push service, or redistribute
20
+ or sell it as a standalone library or SDK.
21
+ - Keep this license notice in copies of the SDK source.
22
+ - The SDK comes with no warranty.
23
+ - Versions published before 3.0.0 remain under the MIT License.
24
+
25
+
26
+ TERMS AND CONDITIONS
27
+
28
+ 1. Definitions
29
+
30
+ "Licensor" means Torsten Labs DOO, Ilindenska 335, 1200 Tetovo, North
31
+ Macedonia.
32
+
33
+ "You" means the individual or legal entity exercising rights under this
34
+ license. If you accept this license on behalf of an organisation, "you"
35
+ includes that organisation.
36
+
37
+ "SDK" means the software in this package or repository published by the
38
+ Licensor under this license, including source code, compiled code, native
39
+ iOS and Android code, type definitions, configuration plugins, examples
40
+ and documentation, together with any updates the Licensor provides under
41
+ this license.
42
+
43
+ "poolse Services" means the hosted services operated by the Licensor under
44
+ the name "poolse", currently offered at https://poolse.dev, including their
45
+ APIs, realtime, calling and push notification infrastructure. It also
46
+ includes any self-hosted or on-premise deployment of poolse that you have
47
+ licensed directly from the Licensor, for as long as that license is in
48
+ effect.
49
+
50
+ "Application" means a website, mobile app, desktop app, server or other
51
+ software product that you develop and that provides material functionality
52
+ of its own beyond the SDK.
53
+
54
+ "Derivative Work" means any modification of the SDK, and any work that
55
+ contains the SDK or a substantial portion of it.
56
+
57
+ 2. License Grant
58
+
59
+ Subject to the terms of this license, the Licensor grants you a worldwide,
60
+ non-exclusive, non-transferable, royalty-free license to:
61
+
62
+ (a) install, use, copy and modify the SDK, and create Derivative Works,
63
+ solely to develop, test and operate Applications that use the poolse
64
+ Services; and
65
+
66
+ (b) distribute the SDK and your Derivative Works, in source or compiled
67
+ form, only as an integrated part of your Applications. This includes
68
+ bundled or minified JavaScript and the native iOS and Android source
69
+ code that must be included for your Application to be compiled.
70
+
71
+ Your Applications may be commercial, and you may charge for them.
72
+
73
+ 3. Restrictions
74
+
75
+ You may not, and may not allow anyone else to:
76
+
77
+ (a) use the SDK or any Derivative Work with, or adapt it to connect to,
78
+ any backend, API or service other than the poolse Services;
79
+
80
+ (b) use the SDK or any Derivative Work to build, offer or operate a
81
+ product or service that competes with the poolse Services, including
82
+ any chat, messaging, realtime, voice or video calling, or push
83
+ notification service or infrastructure offered to third parties;
84
+
85
+ (c) sell, sublicense, rent, lease or distribute the SDK or any Derivative
86
+ Work on its own, or as a library, SDK, framework, component kit or
87
+ developer tool, rather than as an integrated part of an Application;
88
+
89
+ (d) remove, alter or obscure this license, any copyright notice, or any
90
+ other proprietary notice in the SDK; or
91
+
92
+ (e) use the SDK in violation of applicable law or of the terms of service
93
+ that govern your use of the poolse Services.
94
+
95
+ Nothing in this license grants you any right to use the poolse Services
96
+ themselves. Your use of the poolse Services is governed by your separate
97
+ agreement with the Licensor, including its terms of service.
98
+
99
+ 4. Notices
100
+
101
+ Any copy of the SDK or a Derivative Work in source form, including native
102
+ source code distributed with an Application, must keep this license file
103
+ or a clear reference to it. You do not need to display this license to the
104
+ end users of your Application.
105
+
106
+ 5. Contributions
107
+
108
+ If you submit code, documentation or other material to the Licensor for
109
+ inclusion in the SDK (for example, as a pull request), you grant the
110
+ Licensor a perpetual, worldwide, irrevocable, royalty-free license to use,
111
+ modify, sublicense and distribute that material as part of the SDK or any
112
+ other Licensor product, and you confirm that you have the right to grant
113
+ that license.
114
+
115
+ 6. Ownership
116
+
117
+ The SDK is licensed, not sold. The Licensor and its licensors keep all
118
+ rights, title and interest in the SDK, including all intellectual property
119
+ rights. All rights not expressly granted in this license are reserved. The
120
+ names "poolse" and "Torsten Labs" and their logos are not licensed to you
121
+ except as needed to truthfully describe that your Application uses the
122
+ poolse Services.
123
+
124
+ You own your modifications to the SDK, subject to the Licensor's rights in
125
+ the SDK and to the terms of this license.
126
+
127
+ 7. Feedback
128
+
129
+ If you give the Licensor suggestions or feedback about the SDK, the
130
+ Licensor may use them without any obligation to you.
131
+
132
+ 8. Termination
133
+
134
+ This license ends automatically, without notice, if you breach any of its
135
+ terms. If you cure the breach within 30 days after you become aware of it,
136
+ your license is reinstated, unless the Licensor has notified you in writing
137
+ that it is terminating your license, or you have breached this license
138
+ before.
139
+
140
+ When this license ends, you must stop using and distributing the SDK and
141
+ your Derivative Works, and delete all copies in your possession. Copies of
142
+ Applications already delivered to end users before termination may continue
143
+ to be used by those end users. Sections 3, 5, 6, 7, 9, 10, 11 and 12
144
+ survive termination.
145
+
146
+ 9. Disclaimer of Warranty
147
+
148
+ THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTY OF ANY
149
+ KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO THE
150
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
151
+ NON-INFRINGEMENT. THE LICENSOR DOES NOT WARRANT THAT THE SDK WILL BE
152
+ ERROR-FREE, SECURE OR UNINTERRUPTED. YOU USE THE SDK AT YOUR OWN RISK.
153
+
154
+ 10. Limitation of Liability
155
+
156
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL THE
157
+ LICENSOR, ITS AFFILIATES OR ITS CONTRIBUTORS BE LIABLE FOR ANY INDIRECT,
158
+ INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY OR PUNITIVE DAMAGES, OR FOR
159
+ ANY LOSS OF PROFITS, REVENUE, DATA, GOODWILL OR BUSINESS OPPORTUNITY,
160
+ ARISING OUT OF OR IN CONNECTION WITH THIS LICENSE OR THE SDK, WHETHER IN
161
+ CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, EVEN IF ADVISED OF THE
162
+ POSSIBILITY OF SUCH DAMAGES. BECAUSE THE SDK IS PROVIDED FREE OF CHARGE,
163
+ THE LICENSOR'S TOTAL LIABILITY ARISING OUT OF OR IN CONNECTION WITH THIS
164
+ LICENSE OR THE SDK WILL NOT EXCEED ONE HUNDRED EUROS (EUR 100).
165
+
166
+ NOTHING IN THIS LICENSE EXCLUDES OR LIMITS ANY LIABILITY THAT CANNOT BE
167
+ EXCLUDED OR LIMITED UNDER APPLICABLE LAW, INCLUDING LIABILITY FOR WILFUL
168
+ MISCONDUCT OR GROSS NEGLIGENCE.
169
+
170
+ 11. Governing Law and Disputes
171
+
172
+ This license is governed by the laws of the Republic of North Macedonia,
173
+ without regard to its conflict of laws rules. The courts of the Republic of
174
+ North Macedonia have exclusive jurisdiction over any dispute arising out of
175
+ or in connection with this license, except that the Licensor may seek
176
+ injunctive relief to protect its intellectual property in any court of
177
+ competent jurisdiction.
178
+
179
+ 12. General
180
+
181
+ This license is the entire agreement between you and the Licensor about the
182
+ SDK. If any provision is found unenforceable, it will be enforced to the
183
+ maximum extent possible and the remaining provisions stay in effect. A
184
+ failure to enforce a provision is not a waiver. You may not assign this
185
+ license without the Licensor's prior written consent. The Licensor may
186
+ publish new versions of this license; each release of the SDK is governed
187
+ by the version of this license included with it.
188
+
189
+ 13. Earlier Versions
190
+
191
+ Versions of the poolse SDK packages published before version 3.0.0
192
+ (including @poolse/sdk, @poolse/react, @poolse/react-ui and
193
+ @poolse/react-native) were released under the MIT License and remain
194
+ available under the MIT License. This license applies only to versions
195
+ 3.0.0 and later, and to any package first published by the Licensor under
196
+ this license.
197
+
198
+ 14. Contact
199
+
200
+ Questions about this license, or requests for permission beyond it, can be
201
+ sent to legal@poolse.dev.
202
+
203
+ Torsten Labs DOO
204
+ Ilindenska 335
205
+ 1200 Tetovo
206
+ North Macedonia
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  React hooks library for realtime chat. Wraps [`@poolse/sdk`](https://www.npmjs.com/package/@poolse/sdk) in `PoolseProvider` + a typed hook per resource — `useMessages`, `useThread`, `useReactions`, `useTyping`, `usePresence`, `useMembers`, `useAttachmentUpload`. Works in both web React and React Native — same hook surface, same behaviour, same types. No UI: for components see [`@poolse/react-ui`](https://www.npmjs.com/package/@poolse/react-ui) (web) or [`@poolse/react-native`](https://www.npmjs.com/package/@poolse/react-native) (mobile).
4
4
 
5
- > **MIT-licensed alternative to `sendbird-chat-react`, `stream-chat-react`, and `talkjs-react`.** Hooks-only by design — bring your own UI, or drop into the components when you don't want to.
5
+ > **Source-available alternative to `sendbird-chat-react`, `stream-chat-react`, and `talkjs-react`.** Hooks-only by design — bring your own UI, or drop into the components when you don't want to.
6
6
 
7
7
  > **⚠️ Upgrading from 1.x?** See [MIGRATING.md](https://github.com/poolse-hq/js-sdk/blob/main/MIGRATING.md). `useUser`, `useTyping`, `usePresence`, and `useMembers().removeMember` all key by your `external_id` now instead of poolse uuids.
8
8
 
@@ -332,4 +332,4 @@ export { ApiError, AuthError, PoolseError, NetworkError, RateLimitedError };
332
332
 
333
333
  ## License
334
334
 
335
- MIT
335
+ Licensed under the [poolse SDK License](./LICENSE) from 3.0.0 (source-available, for use with the poolse Services only); versions before 3.0.0 remain MIT.
package/dist/index.cjs CHANGED
@@ -1238,384 +1238,6 @@ function useCallRoom(conversationId, opts) {
1238
1238
  toggleMic
1239
1239
  };
1240
1240
  }
1241
- function useAloneWatch({ active, others, graceMs }) {
1242
- const [alone, setAlone] = react.useState(false);
1243
- const seenPeer = react.useRef(false);
1244
- react.useEffect(() => {
1245
- if (!active) {
1246
- seenPeer.current = false;
1247
- setAlone(false);
1248
- return;
1249
- }
1250
- if (others > 0) {
1251
- seenPeer.current = true;
1252
- return;
1253
- }
1254
- if (graceMs <= 0 || !seenPeer.current) return;
1255
- const timer = setTimeout(() => setAlone(true), graceMs);
1256
- return () => clearTimeout(timer);
1257
- }, [active, others, graceMs]);
1258
- return alone;
1259
- }
1260
-
1261
- // src/use-voice-room.ts
1262
- function useVoiceRoom(conversationId, opts = {}) {
1263
- const poolse = usePoolse();
1264
- const [status, setStatus] = react.useState("idle");
1265
- const [participants, setParticipants] = react.useState([]);
1266
- const [muted, setMuted] = react.useState(false);
1267
- const [error, setError] = react.useState(null);
1268
- const optsRef = react.useRef(opts);
1269
- const joined = react.useRef(false);
1270
- const held = react.useRef(null);
1271
- const room = react.useMemo(
1272
- () => conversationId ? poolse.realtime.voice(conversationId, optsRef.current) : null,
1273
- [poolse, conversationId]
1274
- );
1275
- react.useEffect(() => {
1276
- if (!room) return;
1277
- held.current = room;
1278
- setStatus(room.getStatus());
1279
- setParticipants(room.getParticipants());
1280
- setMuted(room.isMuted());
1281
- const offStatus = room.onStatus(setStatus);
1282
- const offRoster = room.onParticipants(setParticipants);
1283
- const offError = room.onError(setError);
1284
- return () => {
1285
- offStatus();
1286
- offRoster();
1287
- offError();
1288
- held.current = null;
1289
- if (joined.current) {
1290
- joined.current = false;
1291
- room.leave();
1292
- }
1293
- };
1294
- }, [room]);
1295
- const join = react.useCallback(async () => {
1296
- const target = room;
1297
- if (!target) return;
1298
- setError(null);
1299
- try {
1300
- await target.join();
1301
- if (held.current !== target) {
1302
- target.leave();
1303
- return;
1304
- }
1305
- joined.current = true;
1306
- } catch (err) {
1307
- setError(err instanceof Error ? err : new Error(String(err)));
1308
- }
1309
- }, [room]);
1310
- const leave = react.useCallback(() => {
1311
- if (!joined.current) return;
1312
- joined.current = false;
1313
- room?.leave();
1314
- }, [room]);
1315
- const toggleMute = react.useCallback(() => {
1316
- if (!room) return;
1317
- setMuted(room.toggleMute());
1318
- }, [room]);
1319
- const alone = useAloneWatch({
1320
- active: status === "connected",
1321
- others: Math.max(0, participants.length - 1),
1322
- graceMs: optsRef.current.aloneGraceMs ?? 1500
1323
- });
1324
- return { status, participants, muted, alone, error, join, leave, toggleMute };
1325
- }
1326
- function useCalls(userId, opts = {}) {
1327
- const ringTimeoutMs = opts.ringTimeoutMs ?? 45e3;
1328
- const poolse = usePoolse();
1329
- const [phase, setPhase] = react.useState("idle");
1330
- const phaseRef = react.useRef("idle");
1331
- phaseRef.current = phase;
1332
- const [incoming, setIncoming] = react.useState(null);
1333
- const [outgoing, setOutgoing] = react.useState(null);
1334
- const [activeConversationId, setActiveConversationId] = react.useState(null);
1335
- const [activeCallId, setActiveCallId] = react.useState(null);
1336
- const [activeMedia, setActiveMedia] = react.useState(null);
1337
- const [error, setError] = react.useState(null);
1338
- const incomingRef = react.useRef(null);
1339
- incomingRef.current = incoming;
1340
- const outgoingRef = react.useRef(null);
1341
- outgoingRef.current = outgoing;
1342
- const activeCallIdRef = react.useRef(null);
1343
- activeCallIdRef.current = activeCallId;
1344
- const isCurrent = react.useCallback((callId) => {
1345
- return callId === activeCallIdRef.current || callId === incomingRef.current?.callId || callId === outgoingRef.current?.callId;
1346
- }, []);
1347
- const rejectedRef = react.useRef(/* @__PURE__ */ new Map());
1348
- const pendingRef = react.useRef(null);
1349
- const actionsRef = react.useRef({
1350
- cancel: async () => {
1351
- },
1352
- decline: async () => {
1353
- }
1354
- });
1355
- const calls = react.useMemo(() => userId ? poolse.realtime.calls(userId) : null, [poolse, userId]);
1356
- const reject = react.useCallback((callId, userId2, kind) => {
1357
- if (phaseRef.current !== "ringing-out") return;
1358
- const out = outgoingRef.current;
1359
- if (!out || out.callId !== callId) return;
1360
- rejectedRef.current.set(userId2, kind);
1361
- const outstanding = out.calleeUserIds.filter((id) => !rejectedRef.current.has(id));
1362
- if (out.calleeUserIds.length > 0 && outstanding.length > 0) return;
1363
- const allBusy = [...rejectedRef.current.values()].every((k) => k === "busy");
1364
- setPhase(allBusy ? "busy" : "declined");
1365
- setOutgoing(null);
1366
- setActiveCallId(null);
1367
- setActiveMedia(null);
1368
- }, []);
1369
- react.useEffect(() => {
1370
- if (!calls) return;
1371
- const offIncoming = calls.onIncoming((call2) => {
1372
- if (call2.callId === incomingRef.current?.callId) return;
1373
- if (call2.callId === activeCallIdRef.current) return;
1374
- if (phaseRef.current !== "idle") {
1375
- void calls.markBusy(call2).catch(() => {
1376
- });
1377
- return;
1378
- }
1379
- setIncoming(call2);
1380
- setPhase("ringing-in");
1381
- });
1382
- const offAccepted = calls.onAccepted((call2) => {
1383
- if (outgoingRef.current && call2.callId !== outgoingRef.current.callId) return;
1384
- setPhase("active");
1385
- setActiveConversationId(call2.conversationId);
1386
- setActiveCallId(call2.callId);
1387
- });
1388
- const offDeclined = calls.onDeclined((call2) => {
1389
- if (!isCurrent(call2.callId)) return;
1390
- reject(call2.callId, call2.userId, "declined");
1391
- });
1392
- const offBusy = calls.onBusy((call2) => {
1393
- if (!isCurrent(call2.callId)) return;
1394
- reject(call2.callId, call2.userId, "busy");
1395
- });
1396
- const offEnded = calls.onEnded((call2) => {
1397
- if (!isCurrent(call2.callId)) return;
1398
- setPhase("idle");
1399
- setIncoming(null);
1400
- setOutgoing(null);
1401
- setActiveConversationId(null);
1402
- setActiveCallId(null);
1403
- setActiveMedia(null);
1404
- });
1405
- const offCancelled = calls.onCancelled((call2) => {
1406
- if (call2.callId !== incomingRef.current?.callId) return;
1407
- setIncoming(null);
1408
- setPhase("idle");
1409
- setActiveCallId(null);
1410
- setActiveMedia(null);
1411
- });
1412
- return () => {
1413
- offIncoming();
1414
- offAccepted();
1415
- offDeclined();
1416
- offBusy();
1417
- offEnded();
1418
- offCancelled();
1419
- };
1420
- }, [calls, isCurrent, reject]);
1421
- react.useEffect(() => {
1422
- if (!calls) return;
1423
- const queued = pendingRef.current;
1424
- if (!queued) return;
1425
- pendingRef.current = null;
1426
- const sent = queued.kind === "accept" ? calls.accept(queued.call) : calls.decline(queued.call);
1427
- void sent.catch((err) => {
1428
- setError(err instanceof Error ? err : new Error(String(err)));
1429
- });
1430
- }, [calls]);
1431
- const call = react.useCallback(
1432
- async (conversationId, media2 = "audio") => {
1433
- if (!calls) return;
1434
- setError(null);
1435
- rejectedRef.current = /* @__PURE__ */ new Map();
1436
- try {
1437
- const placed = await calls.invite(conversationId, media2);
1438
- setOutgoing(placed);
1439
- setActiveCallId(placed.callId);
1440
- setActiveMedia(placed.media);
1441
- setPhase("ringing-out");
1442
- } catch (err) {
1443
- setError(err instanceof Error ? err : new Error(String(err)));
1444
- setPhase("idle");
1445
- }
1446
- },
1447
- [calls]
1448
- );
1449
- const ring = react.useCallback((call2) => {
1450
- if (incomingRef.current?.callId === call2.callId) return;
1451
- if (activeCallIdRef.current === call2.callId) return;
1452
- if (phaseRef.current !== "idle") return;
1453
- setIncoming(call2);
1454
- setPhase("ringing-in");
1455
- }, []);
1456
- const dropped = react.useCallback(
1457
- (callId) => {
1458
- if (pendingRef.current?.call.callId === callId) pendingRef.current = null;
1459
- if (!isCurrent(callId)) return;
1460
- rejectedRef.current = /* @__PURE__ */ new Map();
1461
- setPhase("idle");
1462
- setIncoming(null);
1463
- setOutgoing(null);
1464
- setActiveConversationId(null);
1465
- setActiveCallId(null);
1466
- setActiveMedia(null);
1467
- },
1468
- [isCurrent]
1469
- );
1470
- const accept = react.useCallback(
1471
- async (call2) => {
1472
- const target = call2 ?? incoming;
1473
- if (!target) return;
1474
- if (!calls) {
1475
- pendingRef.current = { kind: "accept", call: target };
1476
- setActiveConversationId(target.conversationId);
1477
- setActiveCallId(target.callId);
1478
- setActiveMedia(target.media);
1479
- setPhase("active");
1480
- setIncoming(null);
1481
- return;
1482
- }
1483
- setActiveConversationId(target.conversationId);
1484
- setActiveCallId(target.callId);
1485
- setActiveMedia(target.media);
1486
- setPhase("active");
1487
- setIncoming(null);
1488
- try {
1489
- await calls.accept(target);
1490
- } catch (err) {
1491
- const message = err instanceof Error ? err.message : String(err);
1492
- if (message.includes("timed out")) return;
1493
- setPhase("idle");
1494
- setActiveConversationId(null);
1495
- setActiveCallId(null);
1496
- setActiveMedia(null);
1497
- setError(err instanceof Error ? err : new Error(String(err)));
1498
- }
1499
- },
1500
- [calls, incoming]
1501
- );
1502
- const decline = react.useCallback(
1503
- async (call2) => {
1504
- const target = call2 ?? incoming;
1505
- if (!target) return;
1506
- if (!calls) {
1507
- pendingRef.current = { kind: "decline", call: target };
1508
- setIncoming(null);
1509
- setActiveCallId(null);
1510
- setActiveMedia(null);
1511
- setPhase("idle");
1512
- return;
1513
- }
1514
- try {
1515
- await calls.decline(target);
1516
- } catch (err) {
1517
- setError(err instanceof Error ? err : new Error(String(err)));
1518
- } finally {
1519
- setIncoming(null);
1520
- setActiveCallId(null);
1521
- setActiveMedia(null);
1522
- setPhase("idle");
1523
- }
1524
- },
1525
- [calls, incoming]
1526
- );
1527
- const cancel = react.useCallback(async () => {
1528
- if (!calls || !outgoing) return;
1529
- try {
1530
- await calls.cancel(outgoing);
1531
- } catch (err) {
1532
- setError(err instanceof Error ? err : new Error(String(err)));
1533
- } finally {
1534
- setOutgoing(null);
1535
- setActiveCallId(null);
1536
- setActiveMedia(null);
1537
- setPhase("idle");
1538
- }
1539
- }, [calls, outgoing]);
1540
- actionsRef.current = { cancel, decline };
1541
- react.useEffect(() => {
1542
- if (ringTimeoutMs <= 0) return;
1543
- if (phase !== "ringing-out" && phase !== "ringing-in") return;
1544
- const outbound = phase === "ringing-out";
1545
- const timer = setTimeout(() => {
1546
- void (outbound ? actionsRef.current.cancel() : actionsRef.current.decline()).finally(() => {
1547
- if (outbound) setPhase("timed-out");
1548
- });
1549
- }, ringTimeoutMs);
1550
- return () => clearTimeout(timer);
1551
- }, [phase, ringTimeoutMs]);
1552
- const othersOnCallRef = react.useRef(0);
1553
- const reportOthersOnCall = react.useCallback((count) => {
1554
- othersOnCallRef.current = count;
1555
- }, []);
1556
- const hangUp = react.useCallback(async () => {
1557
- if (phaseRef.current === "active" && othersOnCallRef.current >= 2) {
1558
- setPhase("idle");
1559
- setIncoming(null);
1560
- setOutgoing(null);
1561
- setActiveConversationId(null);
1562
- setActiveCallId(null);
1563
- setActiveMedia(null);
1564
- setError(null);
1565
- return;
1566
- }
1567
- const conversationId = activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;
1568
- const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;
1569
- try {
1570
- if (!calls || !callId || !conversationId) return;
1571
- if (phase === "ringing-out" && outgoing) {
1572
- await calls.cancel(outgoing);
1573
- } else if (phase === "ringing-in" && incoming) {
1574
- await calls.decline(incoming);
1575
- } else if (phase === "active") {
1576
- await calls.hangUp({ callId, conversationId });
1577
- }
1578
- } catch (err) {
1579
- setError(err instanceof Error ? err : new Error(String(err)));
1580
- } finally {
1581
- setPhase("idle");
1582
- setIncoming(null);
1583
- setOutgoing(null);
1584
- setActiveConversationId(null);
1585
- setActiveCallId(null);
1586
- setActiveMedia(null);
1587
- }
1588
- }, [calls, phase, incoming, outgoing, activeConversationId, activeCallId]);
1589
- const reset = react.useCallback(() => {
1590
- rejectedRef.current = /* @__PURE__ */ new Map();
1591
- pendingRef.current = null;
1592
- setPhase("idle");
1593
- setIncoming(null);
1594
- setOutgoing(null);
1595
- setActiveConversationId(null);
1596
- setActiveCallId(null);
1597
- setActiveMedia(null);
1598
- setError(null);
1599
- }, []);
1600
- const media = incoming?.media ?? outgoing?.media ?? activeMedia ?? "audio";
1601
- return {
1602
- phase,
1603
- incoming,
1604
- outgoing,
1605
- activeConversationId,
1606
- media,
1607
- error,
1608
- call,
1609
- ring,
1610
- dropped,
1611
- accept,
1612
- decline,
1613
- cancel,
1614
- hangUp,
1615
- reportOthersOnCall,
1616
- reset
1617
- };
1618
- }
1619
1241
  function useLiveCall(conversationId) {
1620
1242
  const chat = usePoolse();
1621
1243
  const [call, setCall] = react.useState(null);
@@ -1808,7 +1430,6 @@ exports.sameGroup = sameGroup;
1808
1430
  exports.useAttachmentUpload = useAttachmentUpload;
1809
1431
  exports.useAttachmentUrl = useAttachmentUrl;
1810
1432
  exports.useCallRoom = useCallRoom;
1811
- exports.useCalls = useCalls;
1812
1433
  exports.useConversation = useConversation;
1813
1434
  exports.useConversations = useConversations;
1814
1435
  exports.useLiveCall = useLiveCall;
@@ -1824,6 +1445,5 @@ exports.useRoom = useRoom;
1824
1445
  exports.useThread = useThread;
1825
1446
  exports.useTyping = useTyping;
1826
1447
  exports.useUser = useUser;
1827
- exports.useVoiceRoom = useVoiceRoom;
1828
1448
  //# sourceMappingURL=index.cjs.map
1829
1449
  //# sourceMappingURL=index.cjs.map