@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.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,65 +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;
|
|
1745
|
+
const { built, toRooms, applySocket, useSocketClient: useSocketClient2, debug } = options;
|
|
1660
1746
|
const { useEndpoint: useInnerEndpoint, ...rest } = built;
|
|
1661
1747
|
const useEndpoint = (...useArgs) => {
|
|
1662
|
-
|
|
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
|
+
}
|
|
1663
1756
|
const endpointResult = useInnerEndpoint(
|
|
1664
1757
|
...useArgs
|
|
1665
1758
|
);
|
|
1666
|
-
const argsKey = (0, import_react4.useMemo)(() =>
|
|
1759
|
+
const argsKey = (0, import_react4.useMemo)(() => safeJsonKey(useArgs[0] ?? null), [useArgs]);
|
|
1667
1760
|
const [roomState, setRoomState] = (0, import_react4.useState)(
|
|
1668
1761
|
() => roomsFromData(endpointResult.data, toRooms)
|
|
1669
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;
|
|
1670
1770
|
const roomsKey = (0, import_react4.useMemo)(() => roomState.rooms.join("|"), [roomState.rooms]);
|
|
1671
1771
|
const joinMetaKey = (0, import_react4.useMemo)(
|
|
1672
|
-
() =>
|
|
1772
|
+
() => safeJsonKey(roomState.joinMeta ?? null),
|
|
1673
1773
|
[roomState.joinMeta]
|
|
1674
1774
|
);
|
|
1675
1775
|
const leaveMetaKey = (0, import_react4.useMemo)(
|
|
1676
|
-
() =>
|
|
1776
|
+
() => safeJsonKey(roomState.leaveMeta ?? null),
|
|
1677
1777
|
[roomState.leaveMeta]
|
|
1678
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
|
+
});
|
|
1679
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
|
+
});
|
|
1680
1809
|
const unsubscribe = endpointResult.onReceive((data) => {
|
|
1681
|
-
setRoomState(
|
|
1682
|
-
|
|
1683
|
-
|
|
1810
|
+
setRoomState((prev) => {
|
|
1811
|
+
const next = mergeRoomState(prev, toRooms(data));
|
|
1812
|
+
return roomStateEqual(prev, next) ? prev : next;
|
|
1813
|
+
});
|
|
1684
1814
|
});
|
|
1685
1815
|
return unsubscribe;
|
|
1686
|
-
}, [endpointResult, toRooms]);
|
|
1816
|
+
}, [endpointResult, toRooms, debug]);
|
|
1687
1817
|
(0, import_react4.useEffect)(() => {
|
|
1688
|
-
|
|
1689
|
-
|
|
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
|
|
1690
1830
|
);
|
|
1691
|
-
|
|
1831
|
+
setRoomState((prev) => roomStateEqual(prev, next) ? prev : next);
|
|
1832
|
+
}, [endpointResult.data, toRooms, debug]);
|
|
1692
1833
|
(0, import_react4.useEffect)(() => {
|
|
1693
|
-
|
|
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
|
+
}
|
|
1694
1864
|
const { joinMeta, leaveMeta } = roomState;
|
|
1695
|
-
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
|
+
}
|
|
1696
1874
|
let active = true;
|
|
1875
|
+
dbg2(debug, {
|
|
1876
|
+
type: "room",
|
|
1877
|
+
phase: "join_attempt",
|
|
1878
|
+
rooms: roomState.rooms
|
|
1879
|
+
});
|
|
1697
1880
|
(async () => {
|
|
1698
1881
|
try {
|
|
1699
1882
|
await client.joinRooms(roomState.rooms, joinMeta);
|
|
1700
|
-
} catch {
|
|
1883
|
+
} catch (err) {
|
|
1884
|
+
dbg2(debug, {
|
|
1885
|
+
type: "room",
|
|
1886
|
+
phase: "join_error",
|
|
1887
|
+
rooms: roomState.rooms,
|
|
1888
|
+
err: String(err)
|
|
1889
|
+
});
|
|
1701
1890
|
}
|
|
1702
1891
|
})();
|
|
1703
1892
|
return () => {
|
|
1704
|
-
if (!active
|
|
1893
|
+
if (!active) return;
|
|
1705
1894
|
active = false;
|
|
1706
|
-
|
|
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
|
+
});
|
|
1707
1916
|
});
|
|
1708
1917
|
};
|
|
1709
|
-
}, [
|
|
1710
|
-
client,
|
|
1711
|
-
roomsKey,
|
|
1712
|
-
roomState.joinMeta,
|
|
1713
|
-
roomState.leaveMeta,
|
|
1714
|
-
joinMetaKey,
|
|
1715
|
-
leaveMetaKey
|
|
1716
|
-
]);
|
|
1918
|
+
}, [client, roomsKey, joinMetaKey, leaveMetaKey, debug]);
|
|
1717
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;
|
|
1718
1933
|
const entries = Object.entries(applySocket).filter(
|
|
1719
1934
|
([_event, fn]) => typeof fn === "function"
|
|
1720
1935
|
);
|
|
@@ -1723,8 +1938,12 @@ function buildSocketedRoute(options) {
|
|
|
1723
1938
|
built.setData(
|
|
1724
1939
|
(prev) => {
|
|
1725
1940
|
const next = fn(prev, payload, meta);
|
|
1941
|
+
const nextRoomState = roomsFromData(
|
|
1942
|
+
next,
|
|
1943
|
+
toRooms
|
|
1944
|
+
);
|
|
1726
1945
|
setRoomState(
|
|
1727
|
-
|
|
1946
|
+
(prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
|
|
1728
1947
|
);
|
|
1729
1948
|
return next;
|
|
1730
1949
|
},
|
|
@@ -1733,7 +1952,7 @@ function buildSocketedRoute(options) {
|
|
|
1733
1952
|
})
|
|
1734
1953
|
);
|
|
1735
1954
|
return () => unsubscribes.forEach((u) => u?.());
|
|
1736
|
-
}, [client, applySocket, built, argsKey, toRooms]);
|
|
1955
|
+
}, [client, applySocket, built, argsKey, toRooms, debug]);
|
|
1737
1956
|
return { ...endpointResult, rooms: roomState.rooms };
|
|
1738
1957
|
};
|
|
1739
1958
|
return {
|