@emeryld/rrroutes-client 2.7.12 → 2.8.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/dist/index.cjs +161 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +160 -106
- package/dist/index.mjs.map +1 -1
- package/dist/routesV3.client.types.d.ts +7 -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
|
@@ -1448,6 +1448,12 @@ function createRouteClient(opts) {
|
|
|
1448
1448
|
configurable: false,
|
|
1449
1449
|
writable: false
|
|
1450
1450
|
});
|
|
1451
|
+
Object.defineProperty(built, "metadata", {
|
|
1452
|
+
value: { leaf },
|
|
1453
|
+
enumerable: true,
|
|
1454
|
+
configurable: false,
|
|
1455
|
+
writable: false
|
|
1456
|
+
});
|
|
1451
1457
|
return built;
|
|
1452
1458
|
}
|
|
1453
1459
|
const fetchRaw = async (input) => {
|
|
@@ -1558,25 +1564,76 @@ function useSocketClient() {
|
|
|
1558
1564
|
|
|
1559
1565
|
// src/sockets/socket.client.context.connection.ts
|
|
1560
1566
|
import * as React2 from "react";
|
|
1561
|
-
function
|
|
1567
|
+
function normalizeRooms(rooms) {
|
|
1568
|
+
if (rooms == null) return [];
|
|
1569
|
+
return Array.isArray(rooms) ? rooms : [rooms];
|
|
1570
|
+
}
|
|
1571
|
+
function safeSerialize(value) {
|
|
1572
|
+
try {
|
|
1573
|
+
return JSON.stringify(value) ?? String(value);
|
|
1574
|
+
} catch {
|
|
1575
|
+
return "[unserializable]";
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
function derivePayloadIdentity(payload) {
|
|
1579
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
1580
|
+
const record = payload;
|
|
1581
|
+
const idCandidate = record.id ?? record._id ?? record.notificationId ?? record.uuid ?? record.key;
|
|
1582
|
+
if (typeof idCandidate === "string" || typeof idCandidate === "number" || typeof idCandidate === "bigint") {
|
|
1583
|
+
return String(idCandidate);
|
|
1584
|
+
}
|
|
1585
|
+
return void 0;
|
|
1586
|
+
}
|
|
1587
|
+
function useLatestRef(value) {
|
|
1588
|
+
const ref = React2.useRef(value);
|
|
1589
|
+
React2.useEffect(() => {
|
|
1590
|
+
ref.current = value;
|
|
1591
|
+
}, [value]);
|
|
1592
|
+
return ref;
|
|
1593
|
+
}
|
|
1594
|
+
function useDebugEmitter(debug) {
|
|
1595
|
+
const debugRef = useLatestRef(debug);
|
|
1596
|
+
return React2.useCallback((event) => {
|
|
1597
|
+
const dbg3 = debugRef.current;
|
|
1598
|
+
if (!dbg3?.enabled) return;
|
|
1599
|
+
if (dbg3[event.type] === false) return;
|
|
1600
|
+
const logger = dbg3.logger;
|
|
1601
|
+
if (logger) {
|
|
1602
|
+
try {
|
|
1603
|
+
logger(event);
|
|
1604
|
+
} catch (error) {
|
|
1605
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1606
|
+
console.warn("[socket] debug logger threw", error);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1612
|
+
console.log("[socket]", event);
|
|
1613
|
+
}
|
|
1614
|
+
}, []);
|
|
1615
|
+
}
|
|
1616
|
+
function useSocketRooms(args) {
|
|
1562
1617
|
const {
|
|
1563
|
-
event,
|
|
1564
1618
|
rooms,
|
|
1565
|
-
onMessage,
|
|
1566
|
-
onCleanup,
|
|
1567
1619
|
autoJoin = true,
|
|
1568
1620
|
autoLeave = true,
|
|
1621
|
+
enabled = true,
|
|
1622
|
+
onCleanup,
|
|
1569
1623
|
debug
|
|
1570
1624
|
} = args;
|
|
1571
1625
|
const client = useSocketClient();
|
|
1572
|
-
const normalizedRooms = React2.useMemo(
|
|
1573
|
-
() => rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms],
|
|
1574
|
-
[rooms]
|
|
1575
|
-
);
|
|
1626
|
+
const normalizedRooms = React2.useMemo(() => normalizeRooms(rooms), [rooms]);
|
|
1576
1627
|
const normalizedRoomsKey = React2.useMemo(
|
|
1577
1628
|
() => normalizedRooms.join(""),
|
|
1578
1629
|
[normalizedRooms]
|
|
1579
1630
|
);
|
|
1631
|
+
const joinMetaRef = useLatestRef(args.joinMeta);
|
|
1632
|
+
const leaveMetaRef = useLatestRef(args.leaveMeta);
|
|
1633
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1634
|
+
const debugRef = useLatestRef(debug);
|
|
1635
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1636
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1580
1637
|
const joinMetaKey = React2.useMemo(
|
|
1581
1638
|
() => JSON.stringify(args.joinMeta ?? null),
|
|
1582
1639
|
[args.joinMeta]
|
|
@@ -1585,107 +1642,48 @@ function useSocketConnection(args) {
|
|
|
1585
1642
|
() => JSON.stringify(args.leaveMeta ?? null),
|
|
1586
1643
|
[args.leaveMeta]
|
|
1587
1644
|
);
|
|
1588
|
-
const missingClientWarnedRef = React2.useRef(false);
|
|
1589
|
-
const onMessageRef = React2.useRef(onMessage);
|
|
1590
|
-
const onCleanupRef = React2.useRef(onCleanup);
|
|
1591
|
-
const joinMetaRef = React2.useRef(args.joinMeta);
|
|
1592
|
-
const leaveMetaRef = React2.useRef(args.leaveMeta);
|
|
1593
|
-
const debugRef = React2.useRef(debug);
|
|
1594
|
-
React2.useEffect(() => {
|
|
1595
|
-
onMessageRef.current = onMessage;
|
|
1596
|
-
}, [onMessage]);
|
|
1597
|
-
React2.useEffect(() => {
|
|
1598
|
-
onCleanupRef.current = onCleanup;
|
|
1599
|
-
}, [onCleanup]);
|
|
1600
|
-
React2.useEffect(() => {
|
|
1601
|
-
joinMetaRef.current = args.joinMeta;
|
|
1602
|
-
}, [args.joinMeta]);
|
|
1603
|
-
React2.useEffect(() => {
|
|
1604
|
-
leaveMetaRef.current = args.leaveMeta;
|
|
1605
|
-
}, [args.leaveMeta]);
|
|
1606
|
-
React2.useEffect(() => {
|
|
1607
|
-
debugRef.current = debug;
|
|
1608
|
-
}, [debug]);
|
|
1609
|
-
const emitDebug = React2.useCallback(
|
|
1610
|
-
(event2) => {
|
|
1611
|
-
const dbg3 = debugRef.current;
|
|
1612
|
-
if (!dbg3?.enabled) return;
|
|
1613
|
-
if (dbg3[event2.type] === false) return;
|
|
1614
|
-
const logger = dbg3.logger;
|
|
1615
|
-
if (logger) {
|
|
1616
|
-
try {
|
|
1617
|
-
logger(event2);
|
|
1618
|
-
} catch (error) {
|
|
1619
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1620
|
-
console.warn("[socket] useSocketConnection debug logger threw", error);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
return;
|
|
1624
|
-
}
|
|
1625
|
-
if (typeof console !== "undefined" && typeof console.log === "function") {
|
|
1626
|
-
console.log("[socket] useSocketConnection", event2);
|
|
1627
|
-
}
|
|
1628
|
-
},
|
|
1629
|
-
[]
|
|
1630
|
-
);
|
|
1631
|
-
const reportAsyncError = React2.useCallback(
|
|
1632
|
-
(phase, error) => {
|
|
1633
|
-
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1634
|
-
console.warn(`[socket] useSocketConnection ${phase} failed`, error);
|
|
1635
|
-
}
|
|
1636
|
-
},
|
|
1637
|
-
[]
|
|
1638
|
-
);
|
|
1639
1645
|
React2.useEffect(() => {
|
|
1640
1646
|
emitDebug({
|
|
1641
1647
|
type: "lifecycle",
|
|
1642
1648
|
phase: "effect_start",
|
|
1643
|
-
event,
|
|
1644
1649
|
rooms: normalizedRooms,
|
|
1645
1650
|
autoJoin,
|
|
1646
1651
|
autoLeave
|
|
1647
1652
|
});
|
|
1653
|
+
if (!enabled) {
|
|
1654
|
+
emitDebug({
|
|
1655
|
+
type: "room",
|
|
1656
|
+
phase: "join_skip",
|
|
1657
|
+
rooms: normalizedRooms,
|
|
1658
|
+
reason: "disabled"
|
|
1659
|
+
});
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1648
1662
|
if (!client) {
|
|
1649
1663
|
emitDebug({
|
|
1650
1664
|
type: "lifecycle",
|
|
1651
1665
|
phase: "client_missing",
|
|
1652
|
-
event,
|
|
1653
1666
|
rooms: normalizedRooms,
|
|
1654
1667
|
autoJoin,
|
|
1655
1668
|
autoLeave
|
|
1656
1669
|
});
|
|
1657
|
-
if (debugRef.current?.throwIfClientMissing) {
|
|
1658
|
-
throw new Error(
|
|
1659
|
-
`useSocketConnection("${event}") missing SocketClient. Wrap with <SocketProvider>.`
|
|
1660
|
-
);
|
|
1661
|
-
}
|
|
1662
1670
|
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1663
1671
|
missingClientWarnedRef.current = true;
|
|
1664
|
-
console.warn(
|
|
1665
|
-
`[socket] useSocketConnection("${event}") skipped because SocketClient is null.`
|
|
1666
|
-
);
|
|
1672
|
+
console.warn("[socket] useSocketRooms skipped because SocketClient is null.");
|
|
1667
1673
|
}
|
|
1668
1674
|
return;
|
|
1669
1675
|
}
|
|
1670
1676
|
missingClientWarnedRef.current = false;
|
|
1671
|
-
emitDebug({ type: "subscription", phase: "register", event });
|
|
1672
1677
|
if (autoJoin && normalizedRooms.length > 0) {
|
|
1673
|
-
emitDebug({
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
rooms: normalizedRooms
|
|
1677
|
-
});
|
|
1678
|
-
void client.joinRooms(normalizedRooms, joinMetaRef.current).then(() => {
|
|
1679
|
-
emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms });
|
|
1680
|
-
}).catch((error) => {
|
|
1681
|
-
emitDebug({
|
|
1678
|
+
emitDebug({ type: "room", phase: "join_attempt", rooms: normalizedRooms });
|
|
1679
|
+
void client.joinRooms(normalizedRooms, joinMetaRef.current).then(() => emitDebug({ type: "room", phase: "join_ok", rooms: normalizedRooms })).catch(
|
|
1680
|
+
(error) => emitDebug({
|
|
1682
1681
|
type: "room",
|
|
1683
1682
|
phase: "join_error",
|
|
1684
1683
|
rooms: normalizedRooms,
|
|
1685
1684
|
err: String(error)
|
|
1686
|
-
})
|
|
1687
|
-
|
|
1688
|
-
});
|
|
1685
|
+
})
|
|
1686
|
+
);
|
|
1689
1687
|
} else {
|
|
1690
1688
|
emitDebug({
|
|
1691
1689
|
type: "room",
|
|
@@ -1694,30 +1692,23 @@ function useSocketConnection(args) {
|
|
|
1694
1692
|
reason: autoJoin ? "no_rooms" : "auto_disabled"
|
|
1695
1693
|
});
|
|
1696
1694
|
}
|
|
1697
|
-
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1698
|
-
emitDebug({ type: "subscription", phase: "message", event });
|
|
1699
|
-
onMessageRef.current(payload, meta);
|
|
1700
|
-
});
|
|
1701
1695
|
return () => {
|
|
1702
|
-
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1703
|
-
unsubscribe();
|
|
1704
1696
|
if (autoLeave && normalizedRooms.length > 0) {
|
|
1705
1697
|
emitDebug({
|
|
1706
1698
|
type: "room",
|
|
1707
1699
|
phase: "leave_attempt",
|
|
1708
1700
|
rooms: normalizedRooms
|
|
1709
1701
|
});
|
|
1710
|
-
void client.leaveRooms(normalizedRooms, leaveMetaRef.current).then(
|
|
1711
|
-
emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1712
|
-
|
|
1713
|
-
emitDebug({
|
|
1702
|
+
void client.leaveRooms(normalizedRooms, leaveMetaRef.current).then(
|
|
1703
|
+
() => emitDebug({ type: "room", phase: "leave_ok", rooms: normalizedRooms })
|
|
1704
|
+
).catch(
|
|
1705
|
+
(error) => emitDebug({
|
|
1714
1706
|
type: "room",
|
|
1715
1707
|
phase: "leave_error",
|
|
1716
1708
|
rooms: normalizedRooms,
|
|
1717
1709
|
err: String(error)
|
|
1718
|
-
})
|
|
1719
|
-
|
|
1720
|
-
});
|
|
1710
|
+
})
|
|
1711
|
+
);
|
|
1721
1712
|
} else {
|
|
1722
1713
|
emitDebug({
|
|
1723
1714
|
type: "room",
|
|
@@ -1726,11 +1717,10 @@ function useSocketConnection(args) {
|
|
|
1726
1717
|
reason: autoLeave ? "no_rooms" : "auto_disabled"
|
|
1727
1718
|
});
|
|
1728
1719
|
}
|
|
1729
|
-
|
|
1720
|
+
onCleanupRef.current?.();
|
|
1730
1721
|
emitDebug({
|
|
1731
1722
|
type: "lifecycle",
|
|
1732
1723
|
phase: "effect_cleanup",
|
|
1733
|
-
event,
|
|
1734
1724
|
rooms: normalizedRooms,
|
|
1735
1725
|
autoJoin,
|
|
1736
1726
|
autoLeave
|
|
@@ -1738,16 +1728,79 @@ function useSocketConnection(args) {
|
|
|
1738
1728
|
};
|
|
1739
1729
|
}, [
|
|
1740
1730
|
client,
|
|
1741
|
-
|
|
1731
|
+
enabled,
|
|
1742
1732
|
autoJoin,
|
|
1743
1733
|
autoLeave,
|
|
1744
|
-
emitDebug,
|
|
1745
|
-
reportAsyncError,
|
|
1746
1734
|
normalizedRoomsKey,
|
|
1747
1735
|
joinMetaKey,
|
|
1748
|
-
leaveMetaKey
|
|
1736
|
+
leaveMetaKey,
|
|
1737
|
+
emitDebug
|
|
1749
1738
|
]);
|
|
1750
1739
|
}
|
|
1740
|
+
function useSocketEvent(args) {
|
|
1741
|
+
const {
|
|
1742
|
+
event,
|
|
1743
|
+
onMessage,
|
|
1744
|
+
onCleanup,
|
|
1745
|
+
enabled = true,
|
|
1746
|
+
messageDeduplication,
|
|
1747
|
+
debug
|
|
1748
|
+
} = args;
|
|
1749
|
+
const client = useSocketClient();
|
|
1750
|
+
const onMessageRef = useLatestRef(onMessage);
|
|
1751
|
+
const onCleanupRef = useLatestRef(onCleanup);
|
|
1752
|
+
const messageDeduplicationRef = useLatestRef(messageDeduplication);
|
|
1753
|
+
const debugRef = useLatestRef(debug);
|
|
1754
|
+
const emitDebug = useDebugEmitter(debug);
|
|
1755
|
+
const missingClientWarnedRef = React2.useRef(false);
|
|
1756
|
+
const seenMessageKeysRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
1757
|
+
React2.useEffect(() => {
|
|
1758
|
+
emitDebug({ type: "lifecycle", phase: "effect_start", event });
|
|
1759
|
+
if (!enabled) return;
|
|
1760
|
+
if (!client) {
|
|
1761
|
+
emitDebug({ type: "lifecycle", phase: "client_missing", event });
|
|
1762
|
+
if (debugRef.current?.warnIfClientMissing && !missingClientWarnedRef.current && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1763
|
+
missingClientWarnedRef.current = true;
|
|
1764
|
+
console.warn(`[socket] useSocketEvent("${event}") skipped because SocketClient is null.`);
|
|
1765
|
+
}
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
missingClientWarnedRef.current = false;
|
|
1769
|
+
emitDebug({ type: "subscription", phase: "register", event });
|
|
1770
|
+
const unsubscribe = client.on(event, (payload, meta) => {
|
|
1771
|
+
const dedupeCfg = messageDeduplicationRef.current;
|
|
1772
|
+
if (dedupeCfg !== false) {
|
|
1773
|
+
const ttlMs = Math.max(0, dedupeCfg?.ttlMs ?? 2500);
|
|
1774
|
+
const now = Date.now();
|
|
1775
|
+
const payloadId = derivePayloadIdentity(payload);
|
|
1776
|
+
const dedupeKey = dedupeCfg?.key?.(payload, meta) ?? (payloadId ? `${event}|payload:${payloadId}` : void 0) ?? (meta?.envelope ? `${event}|${String(meta.envelope.eventName)}|${String(meta.envelope.sentAt)}|${safeSerialize(payload)}` : `${event}|${safeSerialize(payload)}`);
|
|
1777
|
+
const prev = seenMessageKeysRef.current.get(dedupeKey);
|
|
1778
|
+
if (typeof prev === "number" && now - prev <= ttlMs) {
|
|
1779
|
+
emitDebug({
|
|
1780
|
+
type: "subscription",
|
|
1781
|
+
phase: "message_dropped_duplicate",
|
|
1782
|
+
event,
|
|
1783
|
+
dedupeKey
|
|
1784
|
+
});
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
seenMessageKeysRef.current.set(dedupeKey, now);
|
|
1788
|
+
}
|
|
1789
|
+
emitDebug({ type: "subscription", phase: "message", event });
|
|
1790
|
+
onMessageRef.current(payload, meta);
|
|
1791
|
+
});
|
|
1792
|
+
return () => {
|
|
1793
|
+
emitDebug({ type: "subscription", phase: "unregister", event });
|
|
1794
|
+
unsubscribe();
|
|
1795
|
+
onCleanupRef.current?.();
|
|
1796
|
+
emitDebug({ type: "lifecycle", phase: "effect_cleanup", event });
|
|
1797
|
+
};
|
|
1798
|
+
}, [client, enabled, event, emitDebug]);
|
|
1799
|
+
}
|
|
1800
|
+
function useSocketConnection(roomsArgs, eventArgs) {
|
|
1801
|
+
useSocketRooms(roomsArgs);
|
|
1802
|
+
useSocketEvent(eventArgs);
|
|
1803
|
+
}
|
|
1751
1804
|
|
|
1752
1805
|
// src/sockets/socket.client.context.debug.ts
|
|
1753
1806
|
function dbg(dbgOpts, e) {
|
|
@@ -2669,7 +2722,9 @@ function buildSocketProvider(args) {
|
|
|
2669
2722
|
}
|
|
2670
2723
|
),
|
|
2671
2724
|
useSocketClient: () => useSocketClient(),
|
|
2672
|
-
|
|
2725
|
+
useSocketRooms: (p) => useSocketRooms(p),
|
|
2726
|
+
useSocketEvent: (p) => useSocketEvent(p),
|
|
2727
|
+
useSocketConnection: (...args2) => useSocketConnection(...args2)
|
|
2673
2728
|
};
|
|
2674
2729
|
}
|
|
2675
2730
|
function SocketProvider(props) {
|
|
@@ -2884,7 +2939,7 @@ function trackHookTrigger2({
|
|
|
2884
2939
|
}
|
|
2885
2940
|
|
|
2886
2941
|
// src/sockets/socketedRoute/socket.client.helper.rooms.ts
|
|
2887
|
-
function
|
|
2942
|
+
function normalizeRooms2(rooms) {
|
|
2888
2943
|
if (rooms == null) return [];
|
|
2889
2944
|
const list = Array.isArray(rooms) ? rooms : [rooms];
|
|
2890
2945
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2909,7 +2964,7 @@ function roomStateEqual(prev, next) {
|
|
|
2909
2964
|
}
|
|
2910
2965
|
function mergeRoomState(prev, toRoomsResult) {
|
|
2911
2966
|
const merged = new Set(prev.rooms);
|
|
2912
|
-
for (const r of
|
|
2967
|
+
for (const r of normalizeRooms2(toRoomsResult.rooms)) merged.add(r);
|
|
2913
2968
|
return {
|
|
2914
2969
|
rooms: Array.from(merged),
|
|
2915
2970
|
joinMeta: toRoomsResult.joinMeta ?? prev.joinMeta,
|
|
@@ -3269,7 +3324,6 @@ export {
|
|
|
3269
3324
|
buildSocketedRoute,
|
|
3270
3325
|
createRouteClient,
|
|
3271
3326
|
defaultFetcher,
|
|
3272
|
-
useSocketClient
|
|
3273
|
-
useSocketConnection
|
|
3327
|
+
useSocketClient
|
|
3274
3328
|
};
|
|
3275
3329
|
//# sourceMappingURL=index.mjs.map
|