@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.cjs
CHANGED
|
@@ -40,7 +40,9 @@ __export(index_exports, {
|
|
|
40
40
|
createRouteClient: () => createRouteClient,
|
|
41
41
|
defaultFetcher: () => defaultFetcher,
|
|
42
42
|
useSocketClient: () => useSocketClient,
|
|
43
|
-
useSocketConnection: () => useSocketConnection
|
|
43
|
+
useSocketConnection: () => useSocketConnection,
|
|
44
|
+
useSocketEvent: () => useSocketEvent,
|
|
45
|
+
useSocketRooms: () => useSocketRooms
|
|
44
46
|
});
|
|
45
47
|
module.exports = __toCommonJS(index_exports);
|
|
46
48
|
|
|
@@ -1581,10 +1583,7 @@ var React = __toESM(require("react"), 1);
|
|
|
1581
1583
|
var SocketCtx = React.createContext(void 0);
|
|
1582
1584
|
function useSocketClient() {
|
|
1583
1585
|
const ctx = React.useContext(SocketCtx);
|
|
1584
|
-
if (typeof ctx === "undefined") {
|
|
1585
|
-
throw new Error("SocketClient not found. Wrap with <SocketProvider>.");
|
|
1586
|
-
}
|
|
1587
|
-
if (!ctx) {
|
|
1586
|
+
if (typeof ctx === "undefined" || !ctx) {
|
|
1588
1587
|
return null;
|
|
1589
1588
|
}
|
|
1590
1589
|
return ctx;
|
|
@@ -1592,25 +1591,67 @@ function useSocketClient() {
|
|
|
1592
1591
|
|
|
1593
1592
|
// src/sockets/socket.client.context.connection.ts
|
|
1594
1593
|
var React2 = __toESM(require("react"), 1);
|
|
1595
|
-
function
|
|
1594
|
+
function normalizeRooms(rooms) {
|
|
1595
|
+
if (rooms == null) return [];
|
|
1596
|
+
return Array.isArray(rooms) ? rooms : [rooms];
|
|
1597
|
+
}
|
|
1598
|
+
function safeSerialize(value) {
|
|
1599
|
+
try {
|
|
1600
|
+
return JSON.stringify(value) ?? String(value);
|
|
1601
|
+
} catch {
|
|
1602
|
+
return "[unserializable]";
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
function useLatestRef(value) {
|
|
1606
|
+
const ref = React2.useRef(value);
|
|
1607
|
+
React2.useEffect(() => {
|
|
1608
|
+
ref.current = value;
|
|
1609
|
+
}, [value]);
|
|
1610
|
+
return ref;
|
|
1611
|
+
}
|
|
1612
|
+
function useDebugEmitter(debug) {
|
|
1613
|
+
const debugRef = useLatestRef(debug);
|
|
1614
|
+
return React2.useCallback((event) => {
|
|
1615
|
+
const dbg3 = debugRef.current;
|
|
1616
|
+
if (!dbg3?.enabled) return;
|
|
1617
|
+
if (dbg3[event.type] === false) return;
|
|
1618
|
+
const logger = dbg3.logger;
|
|
1619
|
+
if (logger) {
|
|
1620
|
+
try {
|
|
1621
|
+
logger(event);
|
|
1622
|
+
} catch (error) {
|
|
1623
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1624
|
+
console.warn("[socket] debug logger threw", error);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1630
|
+
console.log("[socket]", event);
|
|
1631
|
+
}
|
|
1632
|
+
}, []);
|
|
1633
|
+
}
|
|
1634
|
+
function useSocketRooms(args) {
|
|
1596
1635
|
const {
|
|
1597
|
-
event,
|
|
1598
1636
|
rooms,
|
|
1599
|
-
onMessage,
|
|
1600
|
-
onCleanup,
|
|
1601
1637
|
autoJoin = true,
|
|
1602
1638
|
autoLeave = true,
|
|
1639
|
+
enabled = true,
|
|
1640
|
+
onCleanup,
|
|
1603
1641
|
debug
|
|
1604
1642
|
} = args;
|
|
1605
1643
|
const client = useSocketClient();
|
|
1606
|
-
const normalizedRooms = React2.useMemo(
|
|
1607
|
-
() => rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms],
|
|
1608
|
-
[rooms]
|
|
1609
|
-
);
|
|
1644
|
+
const normalizedRooms = React2.useMemo(() => normalizeRooms(rooms), [rooms]);
|
|
1610
1645
|
const normalizedRoomsKey = React2.useMemo(
|
|
1611
1646
|
() => normalizedRooms.join(""),
|
|
1612
1647
|
[normalizedRooms]
|
|
1613
1648
|
);
|
|
1649
|
+
const joinMetaRef = useLatestRef(args.joinMeta);
|
|
1650
|
+
const leaveMetaRef = useLatestRef(args.leaveMeta);
|
|
1651
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1652
|
+
const debugRef = useLatestRef(debug);
|
|
1653
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1654
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1614
1655
|
const joinMetaKey = React2.useMemo(
|
|
1615
1656
|
() => JSON.stringify(args.joinMeta ?? null),
|
|
1616
1657
|
[args.joinMeta]
|
|
@@ -1619,86 +1660,48 @@ function useSocketConnection(args) {
|
|
|
1619
1660
|
() => JSON.stringify(args.leaveMeta ?? null),
|
|
1620
1661
|
[args.leaveMeta]
|
|
1621
1662
|
);
|
|
1622
|
-
const missingClientWarnedRef = React2.useRef(false);
|
|
1623
|
-
const emitDebug = React2.useCallback(
|
|
1624
|
-
(event2) => {
|
|
1625
|
-
if (!debug?.enabled) return;
|
|
1626
|
-
if (debug[event2.type] === false) return;
|
|
1627
|
-
const logger = debug.logger;
|
|
1628
|
-
if (logger) {
|
|
1629
|
-
try {
|
|
1630
|
-
logger(event2);
|
|
1631
|
-
} catch (error) {
|
|
1632
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1633
|
-
console.warn("[socket] useSocketConnection debug logger threw", error);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1639
|
-
console.log("[socket] useSocketConnection", event2);
|
|
1640
|
-
}
|
|
1641
|
-
},
|
|
1642
|
-
[debug]
|
|
1643
|
-
);
|
|
1644
|
-
const reportAsyncError = React2.useCallback(
|
|
1645
|
-
(phase, error) => {
|
|
1646
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1647
|
-
console.warn(`[socket] useSocketConnection ${phase} failed`, error);
|
|
1648
|
-
}
|
|
1649
|
-
},
|
|
1650
|
-
[]
|
|
1651
|
-
);
|
|
1652
1663
|
React2.useEffect(() => {
|
|
1653
1664
|
emitDebug({
|
|
1654
1665
|
type: "lifecycle",
|
|
1655
1666
|
phase: "effect_start",
|
|
1656
|
-
event,
|
|
1657
1667
|
rooms: normalizedRooms,
|
|
1658
1668
|
autoJoin,
|
|
1659
1669
|
autoLeave
|
|
1660
1670
|
});
|
|
1671
|
+
if (!enabled) {
|
|
1672
|
+
emitDebug({
|
|
1673
|
+
type: "room",
|
|
1674
|
+
phase: "join_skip",
|
|
1675
|
+
rooms: normalizedRooms,
|
|
1676
|
+
reason: "disabled"
|
|
1677
|
+
});
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1661
1680
|
if (!client) {
|
|
1662
1681
|
emitDebug({
|
|
1663
1682
|
type: "lifecycle",
|
|
1664
1683
|
phase: "client_missing",
|
|
1665
|
-
event,
|
|
1666
1684
|
rooms: normalizedRooms,
|
|
1667
1685
|
autoJoin,
|
|
1668
1686
|
autoLeave
|
|
1669
1687
|
});
|
|
1670
|
-
if (
|
|
1671
|
-
throw new Error(
|
|
1672
|
-
`useSocketConnection("${event}") missing SocketClient. Wrap with <SocketProvider>.`
|
|
1673
|
-
);
|
|
1674
|
-
}
|
|
1675
|
-
if (debug?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1688
|
+
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1676
1689
|
missingClientWarnedRef.current = true;
|
|
1677
|
-
console.warn(
|
|
1678
|
-
`[socket] useSocketConnection("${event}") skipped because SocketClient is null.`
|
|
1679
|
-
);
|
|
1690
|
+
console.warn("[socket] useSocketRooms skipped because SocketClient is null.");
|
|
1680
1691
|
}
|
|
1681
1692
|
return;
|
|
1682
1693
|
}
|
|
1683
1694
|
missingClientWarnedRef.current = false;
|
|
1684
|
-
emitDebug({ type: "subscription", phase: "register", event });
|
|
1685
1695
|
if (autoJoin && normalizedRooms.length > 0) {
|
|
1686
|
-
emitDebug({
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
rooms: normalizedRooms
|
|
1690
|
-
});
|
|
1691
|
-
void client.joinRooms(normalizedRooms, args.joinMeta).then(() => {
|
|
1692
|
-
emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms });
|
|
1693
|
-
}).catch((error) => {
|
|
1694
|
-
emitDebug({
|
|
1696
|
+
emitDebug({ type: "room", phase: "join_attempt", rooms: normalizedRooms });
|
|
1697
|
+
void client.joinRooms(normalizedRooms, joinMetaRef.current).then(() => emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms })).catch(
|
|
1698
|
+
(error) => emitDebug({
|
|
1695
1699
|
type: "room",
|
|
1696
1700
|
phase: "join_error",
|
|
1697
1701
|
rooms: normalizedRooms,
|
|
1698
1702
|
err: String(error)
|
|
1699
|
-
})
|
|
1700
|
-
|
|
1701
|
-
});
|
|
1703
|
+
})
|
|
1704
|
+
);
|
|
1702
1705
|
} else {
|
|
1703
1706
|
emitDebug({
|
|
1704
1707
|
type: "room",
|
|
@@ -1707,30 +1710,23 @@ function useSocketConnection(args) {
|
|
|
1707
1710
|
reason: autoJoin ? "no_rooms" : "auto_disabled"
|
|
1708
1711
|
});
|
|
1709
1712
|
}
|
|
1710
|
-
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1711
|
-
emitDebug({ type: "subscription", phase: "message", event });
|
|
1712
|
-
onMessage(payload, meta);
|
|
1713
|
-
});
|
|
1714
1713
|
return () => {
|
|
1715
|
-
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1716
|
-
unsubscribe();
|
|
1717
1714
|
if (autoLeave && normalizedRooms.length > 0) {
|
|
1718
1715
|
emitDebug({
|
|
1719
1716
|
type: "room",
|
|
1720
1717
|
phase: "leave_attempt",
|
|
1721
1718
|
rooms: normalizedRooms
|
|
1722
1719
|
});
|
|
1723
|
-
void client.leaveRooms(normalizedRooms,
|
|
1724
|
-
emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1725
|
-
|
|
1726
|
-
emitDebug({
|
|
1720
|
+
void client.leaveRooms(normalizedRooms, leaveMetaRef.current).then(
|
|
1721
|
+
() => emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1722
|
+
).catch(
|
|
1723
|
+
(error) => emitDebug({
|
|
1727
1724
|
type: "room",
|
|
1728
1725
|
phase: "leave_error",
|
|
1729
1726
|
rooms: normalizedRooms,
|
|
1730
1727
|
err: String(error)
|
|
1731
|
-
})
|
|
1732
|
-
|
|
1733
|
-
});
|
|
1728
|
+
})
|
|
1729
|
+
);
|
|
1734
1730
|
} else {
|
|
1735
1731
|
emitDebug({
|
|
1736
1732
|
type: "room",
|
|
@@ -1739,11 +1735,10 @@ function useSocketConnection(args) {
|
|
|
1739
1735
|
reason: autoLeave ? "no_rooms" : "auto_disabled"
|
|
1740
1736
|
});
|
|
1741
1737
|
}
|
|
1742
|
-
|
|
1738
|
+
onCleanupRef.current?.();
|
|
1743
1739
|
emitDebug({
|
|
1744
1740
|
type: "lifecycle",
|
|
1745
1741
|
phase: "effect_cleanup",
|
|
1746
|
-
event,
|
|
1747
1742
|
rooms: normalizedRooms,
|
|
1748
1743
|
autoJoin,
|
|
1749
1744
|
autoLeave
|
|
@@ -1751,19 +1746,78 @@ function useSocketConnection(args) {
|
|
|
1751
1746
|
};
|
|
1752
1747
|
}, [
|
|
1753
1748
|
client,
|
|
1754
|
-
|
|
1755
|
-
onMessage,
|
|
1756
|
-
onCleanup,
|
|
1749
|
+
enabled,
|
|
1757
1750
|
autoJoin,
|
|
1758
1751
|
autoLeave,
|
|
1759
|
-
debug,
|
|
1760
|
-
emitDebug,
|
|
1761
|
-
reportAsyncError,
|
|
1762
1752
|
normalizedRoomsKey,
|
|
1763
1753
|
joinMetaKey,
|
|
1764
|
-
leaveMetaKey
|
|
1754
|
+
leaveMetaKey,
|
|
1755
|
+
emitDebug
|
|
1765
1756
|
]);
|
|
1766
1757
|
}
|
|
1758
|
+
function useSocketEvent(args) {
|
|
1759
|
+
const {
|
|
1760
|
+
event,
|
|
1761
|
+
onMessage,
|
|
1762
|
+
onCleanup,
|
|
1763
|
+
enabled = true,
|
|
1764
|
+
messageDeduplication,
|
|
1765
|
+
debug
|
|
1766
|
+
} = args;
|
|
1767
|
+
const client = useSocketClient();
|
|
1768
|
+
const onMessageRef = useLatestRef(onMessage);
|
|
1769
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1770
|
+
const messageDeduplicationRef = useLatestRef(messageDeduplication);
|
|
1771
|
+
const debugRef = useLatestRef(debug);
|
|
1772
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1773
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1774
|
+
const seenMessageKeysRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
1775
|
+
React2.useEffect(() => {
|
|
1776
|
+
emitDebug({ type: "lifecycle", phase: "effect_start", event });
|
|
1777
|
+
if (!enabled) return;
|
|
1778
|
+
if (!client) {
|
|
1779
|
+
emitDebug({ type: "lifecycle", phase: "client_missing", event });
|
|
1780
|
+
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1781
|
+
missingClientWarnedRef.current = true;
|
|
1782
|
+
console.warn(`[socket] useSocketEvent("${event}") skipped because SocketClient is null.`);
|
|
1783
|
+
}
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
missingClientWarnedRef.current = false;
|
|
1787
|
+
emitDebug({ type: "subscription", phase: "register", event });
|
|
1788
|
+
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1789
|
+
const dedupeCfg = messageDeduplicationRef.current;
|
|
1790
|
+
if (dedupeCfg) {
|
|
1791
|
+
const ttlMs = Math.max(0, dedupeCfg.ttlMs ?? 1500);
|
|
1792
|
+
const now = Date.now();
|
|
1793
|
+
const dedupeKey = dedupeCfg.key?.(payload, meta) ?? (meta?.envelope ? `${event}|${String(meta.envelope.eventName)}|${String(meta.envelope.sentAt)}|${safeSerialize(payload)}` : `${event}|${safeSerialize(payload)}`);
|
|
1794
|
+
const prev = seenMessageKeysRef.current.get(dedupeKey);
|
|
1795
|
+
if (typeof prev === "number" && now - prev <= ttlMs) {
|
|
1796
|
+
emitDebug({
|
|
1797
|
+
type: "subscription",
|
|
1798
|
+
phase: "message_dropped_duplicate",
|
|
1799
|
+
event,
|
|
1800
|
+
dedupeKey
|
|
1801
|
+
});
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
seenMessageKeysRef.current.set(dedupeKey, now);
|
|
1805
|
+
}
|
|
1806
|
+
emitDebug({ type: "subscription", phase: "message", event });
|
|
1807
|
+
onMessageRef.current(payload, meta);
|
|
1808
|
+
});
|
|
1809
|
+
return () => {
|
|
1810
|
+
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1811
|
+
unsubscribe();
|
|
1812
|
+
onCleanupRef.current?.();
|
|
1813
|
+
emitDebug({ type: "lifecycle", phase: "effect_cleanup", event });
|
|
1814
|
+
};
|
|
1815
|
+
}, [client, enabled, event, emitDebug]);
|
|
1816
|
+
}
|
|
1817
|
+
function useSocketConnection(roomsArgs, eventArgs) {
|
|
1818
|
+
useSocketRooms(roomsArgs);
|
|
1819
|
+
useSocketEvent(eventArgs);
|
|
1820
|
+
}
|
|
1767
1821
|
|
|
1768
1822
|
// src/sockets/socket.client.context.debug.ts
|
|
1769
1823
|
function dbg(dbgOpts, e) {
|
|
@@ -2685,7 +2739,9 @@ function buildSocketProvider(args) {
|
|
|
2685
2739
|
}
|
|
2686
2740
|
),
|
|
2687
2741
|
useSocketClient: () => useSocketClient(),
|
|
2688
|
-
|
|
2742
|
+
useSocketRooms: (p) => useSocketRooms(p),
|
|
2743
|
+
useSocketEvent: (p) => useSocketEvent(p),
|
|
2744
|
+
useSocketConnection: (...args2) => useSocketConnection(...args2)
|
|
2689
2745
|
};
|
|
2690
2746
|
}
|
|
2691
2747
|
function SocketProvider(props) {
|
|
@@ -2900,7 +2956,7 @@ function trackHookTrigger2({
|
|
|
2900
2956
|
}
|
|
2901
2957
|
|
|
2902
2958
|
// src/sockets/socketedRoute/socket.client.helper.rooms.ts
|
|
2903
|
-
function
|
|
2959
|
+
function normalizeRooms2(rooms) {
|
|
2904
2960
|
if (rooms == null) return [];
|
|
2905
2961
|
const list = Array.isArray(rooms) ? rooms : [rooms];
|
|
2906
2962
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2925,7 +2981,7 @@ function roomStateEqual(prev, next) {
|
|
|
2925
2981
|
}
|
|
2926
2982
|
function mergeRoomState(prev, toRoomsResult) {
|
|
2927
2983
|
const merged = new Set(prev.rooms);
|
|
2928
|
-
for (const r of
|
|
2984
|
+
for (const r of normalizeRooms2(toRoomsResult.rooms)) merged.add(r);
|
|
2929
2985
|
return {
|
|
2930
2986
|
rooms: Array.from(merged),
|
|
2931
2987
|
joinMeta: toRoomsResult.joinMeta ?? prev.joinMeta,
|
|
@@ -3287,6 +3343,8 @@ function buildSocketedRoute(options) {
|
|
|
3287
3343
|
createRouteClient,
|
|
3288
3344
|
defaultFetcher,
|
|
3289
3345
|
useSocketClient,
|
|
3290
|
-
useSocketConnection
|
|
3346
|
+
useSocketConnection,
|
|
3347
|
+
useSocketEvent,
|
|
3348
|
+
useSocketRooms
|
|
3291
3349
|
});
|
|
3292
3350
|
//# sourceMappingURL=index.cjs.map
|