@emeryld/rrroutes-client 2.6.0 → 2.6.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.
- package/dist/index.cjs +246 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +247 -28
- package/dist/index.mjs.map +1 -1
- package/dist/sockets/socketedRoute/socket.client.helper.d.ts +37 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1568,7 +1568,7 @@ function useSocketConnection(args) {
|
|
|
1568
1568
|
}
|
|
1569
1569
|
|
|
1570
1570
|
// src/sockets/socketedRoute/socket.client.helper.ts
|
|
1571
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
1571
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef5, useState as useState2 } from "react";
|
|
1572
1572
|
function normalizeRooms(rooms) {
|
|
1573
1573
|
if (rooms == null) return [];
|
|
1574
1574
|
const list = Array.isArray(rooms) ? rooms : [rooms];
|
|
@@ -1582,6 +1582,92 @@ function normalizeRooms(rooms) {
|
|
|
1582
1582
|
}
|
|
1583
1583
|
return normalized;
|
|
1584
1584
|
}
|
|
1585
|
+
var objectReferenceIds = /* @__PURE__ */ new WeakMap();
|
|
1586
|
+
var objectReferenceCounter = 0;
|
|
1587
|
+
function describeObjectReference(value) {
|
|
1588
|
+
if (value == null) return null;
|
|
1589
|
+
const valueType = typeof value;
|
|
1590
|
+
if (valueType !== "object" && valueType !== "function") return null;
|
|
1591
|
+
const obj = value;
|
|
1592
|
+
let id = objectReferenceIds.get(obj);
|
|
1593
|
+
if (!id) {
|
|
1594
|
+
id = ++objectReferenceCounter;
|
|
1595
|
+
objectReferenceIds.set(obj, id);
|
|
1596
|
+
}
|
|
1597
|
+
return `ref#${id}`;
|
|
1598
|
+
}
|
|
1599
|
+
function safeJsonKey(value) {
|
|
1600
|
+
try {
|
|
1601
|
+
const serialized = JSON.stringify(value ?? null);
|
|
1602
|
+
return serialized ?? "null";
|
|
1603
|
+
} catch {
|
|
1604
|
+
return "[unserializable]";
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
function arrayShallowEqual(a, b) {
|
|
1608
|
+
if (a.length !== b.length) return false;
|
|
1609
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
1610
|
+
if (a[i] !== b[i]) return false;
|
|
1611
|
+
}
|
|
1612
|
+
return true;
|
|
1613
|
+
}
|
|
1614
|
+
function roomStateEqual(prev, next) {
|
|
1615
|
+
return arrayShallowEqual(prev.rooms, next.rooms) && safeJsonKey(prev.joinMeta) === safeJsonKey(next.joinMeta) && safeJsonKey(prev.leaveMeta) === safeJsonKey(next.leaveMeta);
|
|
1616
|
+
}
|
|
1617
|
+
function safeDescribeHookValue2(value) {
|
|
1618
|
+
if (value == null) return value;
|
|
1619
|
+
const valueType = typeof value;
|
|
1620
|
+
if (valueType === "string" || valueType === "number" || valueType === "boolean") {
|
|
1621
|
+
return value;
|
|
1622
|
+
}
|
|
1623
|
+
if (valueType === "bigint" || valueType === "symbol") return String(value);
|
|
1624
|
+
if (valueType === "function")
|
|
1625
|
+
return `[function ${value.name || "anonymous"}]`;
|
|
1626
|
+
if (Array.isArray(value)) return `[array length=${value.length}]`;
|
|
1627
|
+
const ctorName = value.constructor?.name ?? "object";
|
|
1628
|
+
const keys = Object.keys(value);
|
|
1629
|
+
const keyPreview = keys.slice(0, 4).join(",");
|
|
1630
|
+
const suffix = keys.length > 4 ? ",\u2026" : "";
|
|
1631
|
+
const ref = describeObjectReference(value);
|
|
1632
|
+
return `[${ctorName}${ref ? ` ${ref}` : ""} keys=${keyPreview}${suffix}]`;
|
|
1633
|
+
}
|
|
1634
|
+
function createHookDebugEvent2(prev, next, phase) {
|
|
1635
|
+
const reason = prev ? "change" : "init";
|
|
1636
|
+
const changed = Object.keys(next).reduce((acc, dependency) => {
|
|
1637
|
+
const prevValue = prev ? prev[dependency] : void 0;
|
|
1638
|
+
const nextValue = next[dependency];
|
|
1639
|
+
if (!prev || !Object.is(prevValue, nextValue)) {
|
|
1640
|
+
acc.push({
|
|
1641
|
+
dependency,
|
|
1642
|
+
previous: safeDescribeHookValue2(prevValue),
|
|
1643
|
+
next: safeDescribeHookValue2(nextValue)
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
return acc;
|
|
1647
|
+
}, []);
|
|
1648
|
+
if (!changed.length) return null;
|
|
1649
|
+
return { type: "hook", phase, reason, changes: changed };
|
|
1650
|
+
}
|
|
1651
|
+
function dbg2(debug, event) {
|
|
1652
|
+
if (!debug?.logger) return;
|
|
1653
|
+
if (!debug[event.type]) return;
|
|
1654
|
+
debug.logger(event);
|
|
1655
|
+
}
|
|
1656
|
+
function trackHookTrigger2({
|
|
1657
|
+
ref,
|
|
1658
|
+
phase,
|
|
1659
|
+
debug,
|
|
1660
|
+
snapshot
|
|
1661
|
+
}) {
|
|
1662
|
+
const prev = ref.current;
|
|
1663
|
+
ref.current = snapshot;
|
|
1664
|
+
if (!debug?.logger || !debug?.hook) return;
|
|
1665
|
+
const event = createHookDebugEvent2(prev, snapshot, phase);
|
|
1666
|
+
if (event) dbg2(debug, event);
|
|
1667
|
+
}
|
|
1668
|
+
function isSocketClientUnavailableError(err) {
|
|
1669
|
+
return err instanceof Error && err.message.includes("SocketClient not found");
|
|
1670
|
+
}
|
|
1585
1671
|
function mergeRoomState(prev, toRoomsResult) {
|
|
1586
1672
|
const merged = new Set(prev.rooms);
|
|
1587
1673
|
for (const r of normalizeRooms(toRoomsResult.rooms)) merged.add(r);
|
|
@@ -1620,65 +1706,194 @@ function roomsFromData(data, toRooms) {
|
|
|
1620
1706
|
return state;
|
|
1621
1707
|
}
|
|
1622
1708
|
function buildSocketedRoute(options) {
|
|
1623
|
-
const { built, toRooms, applySocket, useSocketClient: useSocketClient2 } = options;
|
|
1709
|
+
const { built, toRooms, applySocket, useSocketClient: useSocketClient2, debug } = options;
|
|
1624
1710
|
const { useEndpoint: useInnerEndpoint, ...rest } = built;
|
|
1625
1711
|
const useEndpoint = (...useArgs) => {
|
|
1626
|
-
|
|
1712
|
+
let client = null;
|
|
1713
|
+
let socketClientError = null;
|
|
1714
|
+
try {
|
|
1715
|
+
client = useSocketClient2();
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
if (!isSocketClientUnavailableError(err)) throw err;
|
|
1718
|
+
socketClientError = err;
|
|
1719
|
+
}
|
|
1627
1720
|
const endpointResult = useInnerEndpoint(
|
|
1628
1721
|
...useArgs
|
|
1629
1722
|
);
|
|
1630
|
-
const argsKey = useMemo2(() =>
|
|
1723
|
+
const argsKey = useMemo2(() => safeJsonKey(useArgs[0] ?? null), [useArgs]);
|
|
1631
1724
|
const [roomState, setRoomState] = useState2(
|
|
1632
1725
|
() => roomsFromData(endpointResult.data, toRooms)
|
|
1633
1726
|
);
|
|
1727
|
+
const renderCountRef = useRef5(0);
|
|
1728
|
+
const clientReadyRef = useRef5(null);
|
|
1729
|
+
const onReceiveEffectDebugRef = useRef5(null);
|
|
1730
|
+
const deriveRoomsEffectDebugRef = useRef5(null);
|
|
1731
|
+
const joinRoomsEffectDebugRef = useRef5(null);
|
|
1732
|
+
const applySocketEffectDebugRef = useRef5(null);
|
|
1733
|
+
renderCountRef.current += 1;
|
|
1634
1734
|
const roomsKey = useMemo2(() => roomState.rooms.join("|"), [roomState.rooms]);
|
|
1635
1735
|
const joinMetaKey = useMemo2(
|
|
1636
|
-
() =>
|
|
1736
|
+
() => safeJsonKey(roomState.joinMeta ?? null),
|
|
1637
1737
|
[roomState.joinMeta]
|
|
1638
1738
|
);
|
|
1639
1739
|
const leaveMetaKey = useMemo2(
|
|
1640
|
-
() =>
|
|
1740
|
+
() => safeJsonKey(roomState.leaveMeta ?? null),
|
|
1641
1741
|
[roomState.leaveMeta]
|
|
1642
1742
|
);
|
|
1743
|
+
const hasClient = !!client;
|
|
1744
|
+
if (clientReadyRef.current !== hasClient) {
|
|
1745
|
+
clientReadyRef.current = hasClient;
|
|
1746
|
+
dbg2(debug, {
|
|
1747
|
+
type: "client",
|
|
1748
|
+
phase: hasClient ? "ready" : "missing",
|
|
1749
|
+
err: hasClient ? void 0 : String(socketClientError)
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
dbg2(debug, {
|
|
1753
|
+
type: "render",
|
|
1754
|
+
renderCount: renderCountRef.current,
|
|
1755
|
+
hasClient,
|
|
1756
|
+
argsKey,
|
|
1757
|
+
rooms: roomState.rooms,
|
|
1758
|
+
roomsKey,
|
|
1759
|
+
joinMetaKey,
|
|
1760
|
+
leaveMetaKey
|
|
1761
|
+
});
|
|
1643
1762
|
useEffect2(() => {
|
|
1763
|
+
trackHookTrigger2({
|
|
1764
|
+
ref: onReceiveEffectDebugRef,
|
|
1765
|
+
phase: "endpoint_on_receive_effect",
|
|
1766
|
+
debug,
|
|
1767
|
+
snapshot: {
|
|
1768
|
+
endpointResultRef: describeObjectReference(endpointResult),
|
|
1769
|
+
endpointDataRef: describeObjectReference(endpointResult.data),
|
|
1770
|
+
toRoomsRef: describeObjectReference(toRooms)
|
|
1771
|
+
}
|
|
1772
|
+
});
|
|
1644
1773
|
const unsubscribe = endpointResult.onReceive((data) => {
|
|
1645
|
-
setRoomState(
|
|
1646
|
-
|
|
1647
|
-
|
|
1774
|
+
setRoomState((prev) => {
|
|
1775
|
+
const next = mergeRoomState(prev, toRooms(data));
|
|
1776
|
+
return roomStateEqual(prev, next) ? prev : next;
|
|
1777
|
+
});
|
|
1648
1778
|
});
|
|
1649
1779
|
return unsubscribe;
|
|
1650
|
-
}, [endpointResult, toRooms]);
|
|
1780
|
+
}, [endpointResult, toRooms, debug]);
|
|
1651
1781
|
useEffect2(() => {
|
|
1652
|
-
|
|
1653
|
-
|
|
1782
|
+
trackHookTrigger2({
|
|
1783
|
+
ref: deriveRoomsEffectDebugRef,
|
|
1784
|
+
phase: "derive_rooms_effect",
|
|
1785
|
+
debug,
|
|
1786
|
+
snapshot: {
|
|
1787
|
+
endpointDataRef: describeObjectReference(endpointResult.data),
|
|
1788
|
+
toRoomsRef: describeObjectReference(toRooms)
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1791
|
+
const next = roomsFromData(
|
|
1792
|
+
endpointResult.data,
|
|
1793
|
+
toRooms
|
|
1654
1794
|
);
|
|
1655
|
-
|
|
1795
|
+
setRoomState((prev) => roomStateEqual(prev, next) ? prev : next);
|
|
1796
|
+
}, [endpointResult.data, toRooms, debug]);
|
|
1656
1797
|
useEffect2(() => {
|
|
1657
|
-
|
|
1798
|
+
trackHookTrigger2({
|
|
1799
|
+
ref: joinRoomsEffectDebugRef,
|
|
1800
|
+
phase: "join_rooms_effect",
|
|
1801
|
+
debug,
|
|
1802
|
+
snapshot: {
|
|
1803
|
+
hasClient: !!client,
|
|
1804
|
+
clientRef: describeObjectReference(client),
|
|
1805
|
+
roomsKey,
|
|
1806
|
+
joinMetaKey,
|
|
1807
|
+
leaveMetaKey
|
|
1808
|
+
}
|
|
1809
|
+
});
|
|
1810
|
+
if (!client) {
|
|
1811
|
+
dbg2(debug, {
|
|
1812
|
+
type: "room",
|
|
1813
|
+
phase: "join_skip",
|
|
1814
|
+
rooms: roomState.rooms,
|
|
1815
|
+
reason: "socket_client_missing"
|
|
1816
|
+
});
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
if (roomState.rooms.length === 0) {
|
|
1820
|
+
dbg2(debug, {
|
|
1821
|
+
type: "room",
|
|
1822
|
+
phase: "join_skip",
|
|
1823
|
+
rooms: [],
|
|
1824
|
+
reason: "no_rooms"
|
|
1825
|
+
});
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1658
1828
|
const { joinMeta, leaveMeta } = roomState;
|
|
1659
|
-
if (!joinMeta || !leaveMeta)
|
|
1829
|
+
if (!joinMeta || !leaveMeta) {
|
|
1830
|
+
dbg2(debug, {
|
|
1831
|
+
type: "room",
|
|
1832
|
+
phase: "join_skip",
|
|
1833
|
+
rooms: roomState.rooms,
|
|
1834
|
+
reason: "missing_meta"
|
|
1835
|
+
});
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1660
1838
|
let active = true;
|
|
1839
|
+
dbg2(debug, {
|
|
1840
|
+
type: "room",
|
|
1841
|
+
phase: "join_attempt",
|
|
1842
|
+
rooms: roomState.rooms
|
|
1843
|
+
});
|
|
1661
1844
|
(async () => {
|
|
1662
1845
|
try {
|
|
1663
1846
|
await client.joinRooms(roomState.rooms, joinMeta);
|
|
1664
|
-
} catch {
|
|
1847
|
+
} catch (err) {
|
|
1848
|
+
dbg2(debug, {
|
|
1849
|
+
type: "room",
|
|
1850
|
+
phase: "join_error",
|
|
1851
|
+
rooms: roomState.rooms,
|
|
1852
|
+
err: String(err)
|
|
1853
|
+
});
|
|
1665
1854
|
}
|
|
1666
1855
|
})();
|
|
1667
1856
|
return () => {
|
|
1668
|
-
if (!active
|
|
1857
|
+
if (!active) return;
|
|
1669
1858
|
active = false;
|
|
1670
|
-
|
|
1859
|
+
if (roomState.rooms.length === 0) {
|
|
1860
|
+
dbg2(debug, {
|
|
1861
|
+
type: "room",
|
|
1862
|
+
phase: "leave_skip",
|
|
1863
|
+
rooms: [],
|
|
1864
|
+
reason: "no_rooms"
|
|
1865
|
+
});
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
dbg2(debug, {
|
|
1869
|
+
type: "room",
|
|
1870
|
+
phase: "leave_attempt",
|
|
1871
|
+
rooms: roomState.rooms
|
|
1872
|
+
});
|
|
1873
|
+
void client.leaveRooms(roomState.rooms, leaveMeta).catch((err) => {
|
|
1874
|
+
dbg2(debug, {
|
|
1875
|
+
type: "room",
|
|
1876
|
+
phase: "leave_error",
|
|
1877
|
+
rooms: roomState.rooms,
|
|
1878
|
+
err: String(err)
|
|
1879
|
+
});
|
|
1671
1880
|
});
|
|
1672
1881
|
};
|
|
1673
|
-
}, [
|
|
1674
|
-
client,
|
|
1675
|
-
roomsKey,
|
|
1676
|
-
roomState.joinMeta,
|
|
1677
|
-
roomState.leaveMeta,
|
|
1678
|
-
joinMetaKey,
|
|
1679
|
-
leaveMetaKey
|
|
1680
|
-
]);
|
|
1882
|
+
}, [client, roomsKey, joinMetaKey, leaveMetaKey, debug]);
|
|
1681
1883
|
useEffect2(() => {
|
|
1884
|
+
trackHookTrigger2({
|
|
1885
|
+
ref: applySocketEffectDebugRef,
|
|
1886
|
+
phase: "apply_socket_effect",
|
|
1887
|
+
debug,
|
|
1888
|
+
snapshot: {
|
|
1889
|
+
hasClient: !!client,
|
|
1890
|
+
clientRef: describeObjectReference(client),
|
|
1891
|
+
applySocketKeys: Object.keys(applySocket).sort().join(","),
|
|
1892
|
+
argsKey,
|
|
1893
|
+
toRoomsRef: describeObjectReference(toRooms)
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
if (!client) return;
|
|
1682
1897
|
const entries = Object.entries(applySocket).filter(
|
|
1683
1898
|
([_event, fn]) => typeof fn === "function"
|
|
1684
1899
|
);
|
|
@@ -1687,8 +1902,12 @@ function buildSocketedRoute(options) {
|
|
|
1687
1902
|
built.setData(
|
|
1688
1903
|
(prev) => {
|
|
1689
1904
|
const next = fn(prev, payload, meta);
|
|
1905
|
+
const nextRoomState = roomsFromData(
|
|
1906
|
+
next,
|
|
1907
|
+
toRooms
|
|
1908
|
+
);
|
|
1690
1909
|
setRoomState(
|
|
1691
|
-
|
|
1910
|
+
(prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
|
|
1692
1911
|
);
|
|
1693
1912
|
return next;
|
|
1694
1913
|
},
|
|
@@ -1697,7 +1916,7 @@ function buildSocketedRoute(options) {
|
|
|
1697
1916
|
})
|
|
1698
1917
|
);
|
|
1699
1918
|
return () => unsubscribes.forEach((u) => u?.());
|
|
1700
|
-
}, [client, applySocket, built, argsKey, toRooms]);
|
|
1919
|
+
}, [client, applySocket, built, argsKey, toRooms, debug]);
|
|
1701
1920
|
return { ...endpointResult, rooms: roomState.rooms };
|
|
1702
1921
|
};
|
|
1703
1922
|
return {
|