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