@emeryld/rrroutes-client 2.7.11 → 2.7.13
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/dist/index.cjs +151 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +148 -92
- package/dist/index.mjs.map +1 -1
- package/dist/sockets/socket.client.context.connection.d.ts +34 -14
- package/dist/sockets/socket.client.context.d.ts +1 -1
- package/dist/sockets/socket.client.context.provider.d.ts +4 -2
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1550,10 +1550,7 @@ import * as React from "react";
|
|
|
1550
1550
|
var SocketCtx = React.createContext(void 0);
|
|
1551
1551
|
function useSocketClient() {
|
|
1552
1552
|
const ctx = React.useContext(SocketCtx);
|
|
1553
|
-
if (typeof ctx === "undefined") {
|
|
1554
|
-
throw new Error("SocketClient not found. Wrap with <SocketProvider>.");
|
|
1555
|
-
}
|
|
1556
|
-
if (!ctx) {
|
|
1553
|
+
if (typeof ctx === "undefined" || !ctx) {
|
|
1557
1554
|
return null;
|
|
1558
1555
|
}
|
|
1559
1556
|
return ctx;
|
|
@@ -1561,25 +1558,67 @@ function useSocketClient() {
|
|
|
1561
1558
|
|
|
1562
1559
|
// src/sockets/socket.client.context.connection.ts
|
|
1563
1560
|
import * as React2 from "react";
|
|
1564
|
-
function
|
|
1561
|
+
function normalizeRooms(rooms) {
|
|
1562
|
+
if (rooms == null) return [];
|
|
1563
|
+
return Array.isArray(rooms) ? rooms : [rooms];
|
|
1564
|
+
}
|
|
1565
|
+
function safeSerialize(value) {
|
|
1566
|
+
try {
|
|
1567
|
+
return JSON.stringify(value) ?? String(value);
|
|
1568
|
+
} catch {
|
|
1569
|
+
return "[unserializable]";
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
function useLatestRef(value) {
|
|
1573
|
+
const ref = React2.useRef(value);
|
|
1574
|
+
React2.useEffect(() => {
|
|
1575
|
+
ref.current = value;
|
|
1576
|
+
}, [value]);
|
|
1577
|
+
return ref;
|
|
1578
|
+
}
|
|
1579
|
+
function useDebugEmitter(debug) {
|
|
1580
|
+
const debugRef = useLatestRef(debug);
|
|
1581
|
+
return React2.useCallback((event) => {
|
|
1582
|
+
const dbg3 = debugRef.current;
|
|
1583
|
+
if (!dbg3?.enabled) return;
|
|
1584
|
+
if (dbg3[event.type] === false) return;
|
|
1585
|
+
const logger = dbg3.logger;
|
|
1586
|
+
if (logger) {
|
|
1587
|
+
try {
|
|
1588
|
+
logger(event);
|
|
1589
|
+
} catch (error) {
|
|
1590
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1591
|
+
console.warn("[socket] debug logger threw", error);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1597
|
+
console.log("[socket]", event);
|
|
1598
|
+
}
|
|
1599
|
+
}, []);
|
|
1600
|
+
}
|
|
1601
|
+
function useSocketRooms(args) {
|
|
1565
1602
|
const {
|
|
1566
|
-
event,
|
|
1567
1603
|
rooms,
|
|
1568
|
-
onMessage,
|
|
1569
|
-
onCleanup,
|
|
1570
1604
|
autoJoin = true,
|
|
1571
1605
|
autoLeave = true,
|
|
1606
|
+
enabled = true,
|
|
1607
|
+
onCleanup,
|
|
1572
1608
|
debug
|
|
1573
1609
|
} = args;
|
|
1574
1610
|
const client = useSocketClient();
|
|
1575
|
-
const normalizedRooms = React2.useMemo(
|
|
1576
|
-
() => rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms],
|
|
1577
|
-
[rooms]
|
|
1578
|
-
);
|
|
1611
|
+
const normalizedRooms = React2.useMemo(() => normalizeRooms(rooms), [rooms]);
|
|
1579
1612
|
const normalizedRoomsKey = React2.useMemo(
|
|
1580
1613
|
() => normalizedRooms.join(""),
|
|
1581
1614
|
[normalizedRooms]
|
|
1582
1615
|
);
|
|
1616
|
+
const joinMetaRef = useLatestRef(args.joinMeta);
|
|
1617
|
+
const leaveMetaRef = useLatestRef(args.leaveMeta);
|
|
1618
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1619
|
+
const debugRef = useLatestRef(debug);
|
|
1620
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1621
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1583
1622
|
const joinMetaKey = React2.useMemo(
|
|
1584
1623
|
() => JSON.stringify(args.joinMeta ?? null),
|
|
1585
1624
|
[args.joinMeta]
|
|
@@ -1588,86 +1627,48 @@ function useSocketConnection(args) {
|
|
|
1588
1627
|
() => JSON.stringify(args.leaveMeta ?? null),
|
|
1589
1628
|
[args.leaveMeta]
|
|
1590
1629
|
);
|
|
1591
|
-
const missingClientWarnedRef = React2.useRef(false);
|
|
1592
|
-
const emitDebug = React2.useCallback(
|
|
1593
|
-
(event2) => {
|
|
1594
|
-
if (!debug?.enabled) return;
|
|
1595
|
-
if (debug[event2.type] === false) return;
|
|
1596
|
-
const logger = debug.logger;
|
|
1597
|
-
if (logger) {
|
|
1598
|
-
try {
|
|
1599
|
-
logger(event2);
|
|
1600
|
-
} catch (error) {
|
|
1601
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1602
|
-
console.warn("[socket] useSocketConnection debug logger threw", error);
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
return;
|
|
1606
|
-
}
|
|
1607
|
-
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1608
|
-
console.log("[socket] useSocketConnection", event2);
|
|
1609
|
-
}
|
|
1610
|
-
},
|
|
1611
|
-
[debug]
|
|
1612
|
-
);
|
|
1613
|
-
const reportAsyncError = React2.useCallback(
|
|
1614
|
-
(phase, error) => {
|
|
1615
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1616
|
-
console.warn(`[socket] useSocketConnection ${phase} failed`, error);
|
|
1617
|
-
}
|
|
1618
|
-
},
|
|
1619
|
-
[]
|
|
1620
|
-
);
|
|
1621
1630
|
React2.useEffect(() => {
|
|
1622
1631
|
emitDebug({
|
|
1623
1632
|
type: "lifecycle",
|
|
1624
1633
|
phase: "effect_start",
|
|
1625
|
-
event,
|
|
1626
1634
|
rooms: normalizedRooms,
|
|
1627
1635
|
autoJoin,
|
|
1628
1636
|
autoLeave
|
|
1629
1637
|
});
|
|
1638
|
+
if (!enabled) {
|
|
1639
|
+
emitDebug({
|
|
1640
|
+
type: "room",
|
|
1641
|
+
phase: "join_skip",
|
|
1642
|
+
rooms: normalizedRooms,
|
|
1643
|
+
reason: "disabled"
|
|
1644
|
+
});
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1630
1647
|
if (!client) {
|
|
1631
1648
|
emitDebug({
|
|
1632
1649
|
type: "lifecycle",
|
|
1633
1650
|
phase: "client_missing",
|
|
1634
|
-
event,
|
|
1635
1651
|
rooms: normalizedRooms,
|
|
1636
1652
|
autoJoin,
|
|
1637
1653
|
autoLeave
|
|
1638
1654
|
});
|
|
1639
|
-
if (
|
|
1640
|
-
throw new Error(
|
|
1641
|
-
`useSocketConnection("${event}") missing SocketClient. Wrap with <SocketProvider>.`
|
|
1642
|
-
);
|
|
1643
|
-
}
|
|
1644
|
-
if (debug?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1655
|
+
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1645
1656
|
missingClientWarnedRef.current = true;
|
|
1646
|
-
console.warn(
|
|
1647
|
-
`[socket] useSocketConnection("${event}") skipped because SocketClient is null.`
|
|
1648
|
-
);
|
|
1657
|
+
console.warn("[socket] useSocketRooms skipped because SocketClient is null.");
|
|
1649
1658
|
}
|
|
1650
1659
|
return;
|
|
1651
1660
|
}
|
|
1652
1661
|
missingClientWarnedRef.current = false;
|
|
1653
|
-
emitDebug({ type: "subscription", phase: "register", event });
|
|
1654
1662
|
if (autoJoin && normalizedRooms.length > 0) {
|
|
1655
|
-
emitDebug({
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
rooms: normalizedRooms
|
|
1659
|
-
});
|
|
1660
|
-
void client.joinRooms(normalizedRooms, args.joinMeta).then(() => {
|
|
1661
|
-
emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms });
|
|
1662
|
-
}).catch((error) => {
|
|
1663
|
-
emitDebug({
|
|
1663
|
+
emitDebug({ type: "room", phase: "join_attempt", rooms: normalizedRooms });
|
|
1664
|
+
void client.joinRooms(normalizedRooms, joinMetaRef.current).then(() => emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms })).catch(
|
|
1665
|
+
(error) => emitDebug({
|
|
1664
1666
|
type: "room",
|
|
1665
1667
|
phase: "join_error",
|
|
1666
1668
|
rooms: normalizedRooms,
|
|
1667
1669
|
err: String(error)
|
|
1668
|
-
})
|
|
1669
|
-
|
|
1670
|
-
});
|
|
1670
|
+
})
|
|
1671
|
+
);
|
|
1671
1672
|
} else {
|
|
1672
1673
|
emitDebug({
|
|
1673
1674
|
type: "room",
|
|
@@ -1676,30 +1677,23 @@ function useSocketConnection(args) {
|
|
|
1676
1677
|
reason: autoJoin ? "no_rooms" : "auto_disabled"
|
|
1677
1678
|
});
|
|
1678
1679
|
}
|
|
1679
|
-
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1680
|
-
emitDebug({ type: "subscription", phase: "message", event });
|
|
1681
|
-
onMessage(payload, meta);
|
|
1682
|
-
});
|
|
1683
1680
|
return () => {
|
|
1684
|
-
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1685
|
-
unsubscribe();
|
|
1686
1681
|
if (autoLeave && normalizedRooms.length > 0) {
|
|
1687
1682
|
emitDebug({
|
|
1688
1683
|
type: "room",
|
|
1689
1684
|
phase: "leave_attempt",
|
|
1690
1685
|
rooms: normalizedRooms
|
|
1691
1686
|
});
|
|
1692
|
-
void client.leaveRooms(normalizedRooms,
|
|
1693
|
-
emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1694
|
-
|
|
1695
|
-
emitDebug({
|
|
1687
|
+
void client.leaveRooms(normalizedRooms, leaveMetaRef.current).then(
|
|
1688
|
+
() => emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1689
|
+
).catch(
|
|
1690
|
+
(error) => emitDebug({
|
|
1696
1691
|
type: "room",
|
|
1697
1692
|
phase: "leave_error",
|
|
1698
1693
|
rooms: normalizedRooms,
|
|
1699
1694
|
err: String(error)
|
|
1700
|
-
})
|
|
1701
|
-
|
|
1702
|
-
});
|
|
1695
|
+
})
|
|
1696
|
+
);
|
|
1703
1697
|
} else {
|
|
1704
1698
|
emitDebug({
|
|
1705
1699
|
type: "room",
|
|
@@ -1708,11 +1702,10 @@ function useSocketConnection(args) {
|
|
|
1708
1702
|
reason: autoLeave ? "no_rooms" : "auto_disabled"
|
|
1709
1703
|
});
|
|
1710
1704
|
}
|
|
1711
|
-
|
|
1705
|
+
onCleanupRef.current?.();
|
|
1712
1706
|
emitDebug({
|
|
1713
1707
|
type: "lifecycle",
|
|
1714
1708
|
phase: "effect_cleanup",
|
|
1715
|
-
event,
|
|
1716
1709
|
rooms: normalizedRooms,
|
|
1717
1710
|
autoJoin,
|
|
1718
1711
|
autoLeave
|
|
@@ -1720,19 +1713,78 @@ function useSocketConnection(args) {
|
|
|
1720
1713
|
};
|
|
1721
1714
|
}, [
|
|
1722
1715
|
client,
|
|
1723
|
-
|
|
1724
|
-
onMessage,
|
|
1725
|
-
onCleanup,
|
|
1716
|
+
enabled,
|
|
1726
1717
|
autoJoin,
|
|
1727
1718
|
autoLeave,
|
|
1728
|
-
debug,
|
|
1729
|
-
emitDebug,
|
|
1730
|
-
reportAsyncError,
|
|
1731
1719
|
normalizedRoomsKey,
|
|
1732
1720
|
joinMetaKey,
|
|
1733
|
-
leaveMetaKey
|
|
1721
|
+
leaveMetaKey,
|
|
1722
|
+
emitDebug
|
|
1734
1723
|
]);
|
|
1735
1724
|
}
|
|
1725
|
+
function useSocketEvent(args) {
|
|
1726
|
+
const {
|
|
1727
|
+
event,
|
|
1728
|
+
onMessage,
|
|
1729
|
+
onCleanup,
|
|
1730
|
+
enabled = true,
|
|
1731
|
+
messageDeduplication,
|
|
1732
|
+
debug
|
|
1733
|
+
} = args;
|
|
1734
|
+
const client = useSocketClient();
|
|
1735
|
+
const onMessageRef = useLatestRef(onMessage);
|
|
1736
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1737
|
+
const messageDeduplicationRef = useLatestRef(messageDeduplication);
|
|
1738
|
+
const debugRef = useLatestRef(debug);
|
|
1739
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1740
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1741
|
+
const seenMessageKeysRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
1742
|
+
React2.useEffect(() => {
|
|
1743
|
+
emitDebug({ type: "lifecycle", phase: "effect_start", event });
|
|
1744
|
+
if (!enabled) return;
|
|
1745
|
+
if (!client) {
|
|
1746
|
+
emitDebug({ type: "lifecycle", phase: "client_missing", event });
|
|
1747
|
+
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1748
|
+
missingClientWarnedRef.current = true;
|
|
1749
|
+
console.warn(`[socket] useSocketEvent("${event}") skipped because SocketClient is null.`);
|
|
1750
|
+
}
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
missingClientWarnedRef.current = false;
|
|
1754
|
+
emitDebug({ type: "subscription", phase: "register", event });
|
|
1755
|
+
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1756
|
+
const dedupeCfg = messageDeduplicationRef.current;
|
|
1757
|
+
if (dedupeCfg) {
|
|
1758
|
+
const ttlMs = Math.max(0, dedupeCfg.ttlMs ?? 1500);
|
|
1759
|
+
const now = Date.now();
|
|
1760
|
+
const dedupeKey = dedupeCfg.key?.(payload, meta) ?? (meta?.envelope ? `${event}|${String(meta.envelope.eventName)}|${String(meta.envelope.sentAt)}|${safeSerialize(payload)}` : `${event}|${safeSerialize(payload)}`);
|
|
1761
|
+
const prev = seenMessageKeysRef.current.get(dedupeKey);
|
|
1762
|
+
if (typeof prev === "number" && now - prev <= ttlMs) {
|
|
1763
|
+
emitDebug({
|
|
1764
|
+
type: "subscription",
|
|
1765
|
+
phase: "message_dropped_duplicate",
|
|
1766
|
+
event,
|
|
1767
|
+
dedupeKey
|
|
1768
|
+
});
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
seenMessageKeysRef.current.set(dedupeKey, now);
|
|
1772
|
+
}
|
|
1773
|
+
emitDebug({ type: "subscription", phase: "message", event });
|
|
1774
|
+
onMessageRef.current(payload, meta);
|
|
1775
|
+
});
|
|
1776
|
+
return () => {
|
|
1777
|
+
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1778
|
+
unsubscribe();
|
|
1779
|
+
onCleanupRef.current?.();
|
|
1780
|
+
emitDebug({ type: "lifecycle", phase: "effect_cleanup", event });
|
|
1781
|
+
};
|
|
1782
|
+
}, [client, enabled, event, emitDebug]);
|
|
1783
|
+
}
|
|
1784
|
+
function useSocketConnection(roomsArgs, eventArgs) {
|
|
1785
|
+
useSocketRooms(roomsArgs);
|
|
1786
|
+
useSocketEvent(eventArgs);
|
|
1787
|
+
}
|
|
1736
1788
|
|
|
1737
1789
|
// src/sockets/socket.client.context.debug.ts
|
|
1738
1790
|
function dbg(dbgOpts, e) {
|
|
@@ -2654,7 +2706,9 @@ function buildSocketProvider(args) {
|
|
|
2654
2706
|
}
|
|
2655
2707
|
),
|
|
2656
2708
|
useSocketClient: () => useSocketClient(),
|
|
2657
|
-
|
|
2709
|
+
useSocketRooms: (p) => useSocketRooms(p),
|
|
2710
|
+
useSocketEvent: (p) => useSocketEvent(p),
|
|
2711
|
+
useSocketConnection: (...args2) => useSocketConnection(...args2)
|
|
2658
2712
|
};
|
|
2659
2713
|
}
|
|
2660
2714
|
function SocketProvider(props) {
|
|
@@ -2869,7 +2923,7 @@ function trackHookTrigger2({
|
|
|
2869
2923
|
}
|
|
2870
2924
|
|
|
2871
2925
|
// src/sockets/socketedRoute/socket.client.helper.rooms.ts
|
|
2872
|
-
function
|
|
2926
|
+
function normalizeRooms2(rooms) {
|
|
2873
2927
|
if (rooms == null) return [];
|
|
2874
2928
|
const list = Array.isArray(rooms) ? rooms : [rooms];
|
|
2875
2929
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2894,7 +2948,7 @@ function roomStateEqual(prev, next) {
|
|
|
2894
2948
|
}
|
|
2895
2949
|
function mergeRoomState(prev, toRoomsResult) {
|
|
2896
2950
|
const merged = new Set(prev.rooms);
|
|
2897
|
-
for (const r of
|
|
2951
|
+
for (const r of normalizeRooms2(toRoomsResult.rooms)) merged.add(r);
|
|
2898
2952
|
return {
|
|
2899
2953
|
rooms: Array.from(merged),
|
|
2900
2954
|
joinMeta: toRoomsResult.joinMeta ?? prev.joinMeta,
|
|
@@ -3255,6 +3309,8 @@ export {
|
|
|
3255
3309
|
createRouteClient,
|
|
3256
3310
|
defaultFetcher,
|
|
3257
3311
|
useSocketClient,
|
|
3258
|
-
useSocketConnection
|
|
3312
|
+
useSocketConnection,
|
|
3313
|
+
useSocketEvent,
|
|
3314
|
+
useSocketRooms
|
|
3259
3315
|
};
|
|
3260
3316
|
//# sourceMappingURL=index.mjs.map
|