@emeryld/rrroutes-client 2.6.6 → 2.6.8

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.mjs CHANGED
@@ -1,5 +1,12 @@
1
1
  "use client";
2
2
 
3
+ // src/routesV3.client.ts
4
+ import {
5
+ lowProfileParse as lowProfileParse5
6
+ } from "@emeryld/rrroutes-contract";
7
+ import { keepPreviousData as keepPreviousData3, useQuery as useQuery2 } from "@tanstack/react-query";
8
+ import { useCallback as useCallback4, useRef as useRef4 } from "react";
9
+
3
10
  // src/routesV3.client.fetch.ts
4
11
  var HttpError = class extends Error {
5
12
  constructor({
@@ -1095,6 +1102,7 @@ function buildMutationLeaf(leaf, rqOpts, env) {
1095
1102
  }
1096
1103
 
1097
1104
  // src/routesV3.client.ts
1105
+ var BUILT_LEAF_META = "__rrroutesLeaf";
1098
1106
  var defaultDebugLogger = (event) => {
1099
1107
  if (typeof console === "undefined") return;
1100
1108
  const fn = console.debug ?? console.log;
@@ -1161,6 +1169,7 @@ function createRouteClient(opts) {
1161
1169
  const fetcher = opts.fetcher ?? defaultFetcher;
1162
1170
  const baseUrl = opts.baseUrl;
1163
1171
  const environment = opts.environment ?? void 0;
1172
+ const validateResponses = opts.validateResponses ?? true;
1164
1173
  const { emit: emitDebug, mode: debugMode } = createDebugEmitter(
1165
1174
  opts.debug,
1166
1175
  environment
@@ -1175,13 +1184,23 @@ function createRouteClient(opts) {
1175
1184
  await queryClient.invalidateQueries({ queryKey, exact });
1176
1185
  emitDebug({ type: "invalidate", key: queryKey, exact });
1177
1186
  }
1187
+ const toArgsTuple2 = (args) => typeof args === "undefined" ? [] : [args];
1188
+ const getBuiltLeaf = (built) => {
1189
+ const leaf = built[BUILT_LEAF_META];
1190
+ if (!leaf) {
1191
+ throw new Error(
1192
+ "buildBranch(...) expects endpoints created with this route client via client.build(...)."
1193
+ );
1194
+ }
1195
+ return leaf;
1196
+ };
1197
+ const encodeLeafKey = (leaf) => encodeURIComponent(`${leaf.method.toUpperCase()} ${leaf.path}`);
1178
1198
  function buildInternal(leaf, rqOpts, meta) {
1179
1199
  const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;
1180
1200
  const debugName = meta?.name;
1181
1201
  const emit = (event) => emitDebug(event, debugName);
1182
1202
  const isGet = leaf.method === "get";
1183
1203
  const isFeed = !!leaf.cfg.feed;
1184
- const validateResponses = opts.validateResponses ?? true;
1185
1204
  const env = {
1186
1205
  baseUrl,
1187
1206
  validateResponses,
@@ -1192,25 +1211,33 @@ function createRouteClient(opts) {
1192
1211
  isVerboseDebug,
1193
1212
  leafLabel
1194
1213
  };
1214
+ let built;
1195
1215
  if (isGet && isFeed) {
1196
- return buildInfiniteGetLeaf(
1216
+ built = buildInfiniteGetLeaf(
1197
1217
  leaf,
1198
1218
  rqOpts,
1199
1219
  env
1200
1220
  );
1201
- }
1202
- if (isGet) {
1203
- return buildGetLeaf(
1221
+ } else if (isGet) {
1222
+ built = buildGetLeaf(
1223
+ leaf,
1224
+ rqOpts,
1225
+ env
1226
+ );
1227
+ } else {
1228
+ built = buildMutationLeaf(
1204
1229
  leaf,
1205
1230
  rqOpts,
1206
1231
  env
1207
1232
  );
1208
1233
  }
1209
- return buildMutationLeaf(
1210
- leaf,
1211
- rqOpts,
1212
- env
1213
- );
1234
+ Object.defineProperty(built, BUILT_LEAF_META, {
1235
+ value: leaf,
1236
+ enumerable: false,
1237
+ configurable: false,
1238
+ writable: false
1239
+ });
1240
+ return built;
1214
1241
  }
1215
1242
  const fetchRaw = async (input) => {
1216
1243
  const { path, method, query, body, params } = input;
@@ -1279,11 +1306,151 @@ function createRouteClient(opts) {
1279
1306
  throw error;
1280
1307
  }
1281
1308
  };
1309
+ const buildBranchInternal = (leaves, options) => {
1310
+ const batchMethod = options.method ?? "POST";
1311
+ const defaultHeaders = options.headers;
1312
+ const getQueryKeys = (input) => {
1313
+ const out = {};
1314
+ const argsByLeaf = input ?? {};
1315
+ for (const [alias, built] of Object.entries(leaves)) {
1316
+ const args = argsByLeaf[alias];
1317
+ out[alias] = built.getQueryKeys(...toArgsTuple2(args));
1318
+ }
1319
+ return out;
1320
+ };
1321
+ const invalidateBranch = async (input) => {
1322
+ const argsByLeaf = input ?? {};
1323
+ await Promise.all(
1324
+ Object.entries(leaves).map(([alias, built]) => {
1325
+ const args = argsByLeaf[alias];
1326
+ return built.invalidate(...toArgsTuple2(args));
1327
+ })
1328
+ );
1329
+ };
1330
+ const setDataBranch = (input) => {
1331
+ const out = {};
1332
+ for (const [alias, def] of Object.entries(input)) {
1333
+ if (!def) continue;
1334
+ const built = leaves[alias];
1335
+ if (!built) continue;
1336
+ out[alias] = built.setData(
1337
+ def.updater,
1338
+ ...toArgsTuple2(def.args)
1339
+ );
1340
+ }
1341
+ return out;
1342
+ };
1343
+ const fetchBranch = async (input) => {
1344
+ const payload = {};
1345
+ const keyByAlias = /* @__PURE__ */ new Map();
1346
+ for (const [aliasRaw, built] of Object.entries(leaves)) {
1347
+ const alias = aliasRaw;
1348
+ const leaf = getBuiltLeaf(built);
1349
+ const encodedLeaf = encodeLeafKey(leaf);
1350
+ keyByAlias.set(alias, encodedLeaf);
1351
+ const branchInput = input[alias];
1352
+ const args = branchInput?.args;
1353
+ const body = branchInput?.body;
1354
+ payload[encodedLeaf] = {
1355
+ ...args?.params !== void 0 ? { params: args.params } : {},
1356
+ ...args?.query !== void 0 ? { query: args.query } : {},
1357
+ ...body !== void 0 ? { body } : {}
1358
+ };
1359
+ }
1360
+ const batchResponse = await fetchRaw({
1361
+ path: options.path,
1362
+ method: batchMethod,
1363
+ body: payload,
1364
+ headers: defaultHeaders
1365
+ });
1366
+ const rawData = batchResponse.data;
1367
+ if (!rawData || typeof rawData !== "object" || Array.isArray(rawData)) {
1368
+ throw new Error(
1369
+ "Batch response must be a plain object keyed by encoded route keys."
1370
+ );
1371
+ }
1372
+ const mapped = {};
1373
+ for (const [aliasRaw, built] of Object.entries(leaves)) {
1374
+ const alias = aliasRaw;
1375
+ const encodedLeaf = keyByAlias.get(alias);
1376
+ if (!encodedLeaf) {
1377
+ throw new Error(
1378
+ `Internal batch error: missing encoded key for alias "${String(alias)}".`
1379
+ );
1380
+ }
1381
+ if (!(encodedLeaf in rawData)) {
1382
+ throw new Error(`Batch response missing key "${encodedLeaf}".`);
1383
+ }
1384
+ const leaf = getBuiltLeaf(built);
1385
+ const rawLeafData = rawData[encodedLeaf];
1386
+ const parsedLeafData = validateResponses && leaf.cfg.outputSchema ? lowProfileParse5(leaf.cfg.outputSchema, rawLeafData) : rawLeafData;
1387
+ if (validateResponses && !leaf.cfg.outputSchema) {
1388
+ throw new Error(
1389
+ `No output schema defined for leaf ${leaf.method.toUpperCase()} ${leaf.path}, cannot validate batch response.`
1390
+ );
1391
+ }
1392
+ ;
1393
+ mapped[aliasRaw] = parsedLeafData;
1394
+ }
1395
+ return mapped;
1396
+ };
1397
+ const useEndpoint = (input, rqOpts) => {
1398
+ const queryKeys = getQueryKeys(input);
1399
+ const branchQueryKey = [
1400
+ "batch",
1401
+ String(batchMethod).toLowerCase(),
1402
+ options.path,
1403
+ queryKeys
1404
+ ];
1405
+ const { onReceive, ...useQueryOptions } = rqOpts ?? {};
1406
+ const listenersRef = useRef4(
1407
+ /* @__PURE__ */ new Set()
1408
+ );
1409
+ const notifyOnReceive = useCallback4(
1410
+ (data) => {
1411
+ onReceive?.(data);
1412
+ listenersRef.current.forEach((listener) => listener(data));
1413
+ },
1414
+ [onReceive]
1415
+ );
1416
+ const registerOnReceive = useCallback4(
1417
+ (listener) => {
1418
+ listenersRef.current.add(listener);
1419
+ return () => {
1420
+ listenersRef.current.delete(listener);
1421
+ };
1422
+ },
1423
+ []
1424
+ );
1425
+ const queryResult = useQuery2(
1426
+ {
1427
+ ...useQueryOptions,
1428
+ queryKey: branchQueryKey,
1429
+ placeholderData: useQueryOptions.placeholderData ?? keepPreviousData3,
1430
+ queryFn: async () => {
1431
+ const result = await fetchBranch(input);
1432
+ notifyOnReceive(result);
1433
+ return result;
1434
+ }
1435
+ },
1436
+ queryClient
1437
+ );
1438
+ return { ...queryResult, onReceive: registerOnReceive };
1439
+ };
1440
+ return {
1441
+ fetch: fetchBranch,
1442
+ useEndpoint,
1443
+ getQueryKeys,
1444
+ invalidate: invalidateBranch,
1445
+ setData: setDataBranch
1446
+ };
1447
+ };
1282
1448
  return {
1283
1449
  queryClient,
1284
1450
  invalidate,
1285
1451
  fetch: fetchRaw,
1286
- build: buildInternal
1452
+ build: buildInternal,
1453
+ buildBranch: buildBranchInternal
1287
1454
  };
1288
1455
  }
1289
1456
  function buildRouter(routeClient, routes) {
@@ -1295,6 +1462,168 @@ function buildRouter(routeClient, routes) {
1295
1462
  ));
1296
1463
  }
1297
1464
 
1465
+ // src/sockets/socket.client.context.provider.tsx
1466
+ import * as React3 from "react";
1467
+
1468
+ // src/sockets/socket.client.context.client.ts
1469
+ import * as React from "react";
1470
+ var SocketCtx = React.createContext(null);
1471
+ function useSocketClient() {
1472
+ const ctx = React.useContext(SocketCtx);
1473
+ if (!ctx)
1474
+ throw new Error("SocketClient not found. Wrap with <SocketProvider>.");
1475
+ return ctx;
1476
+ }
1477
+
1478
+ // src/sockets/socket.client.context.connection.ts
1479
+ import * as React2 from "react";
1480
+ function useSocketConnection(args) {
1481
+ const {
1482
+ event,
1483
+ rooms,
1484
+ onMessage,
1485
+ onCleanup,
1486
+ autoJoin = true,
1487
+ autoLeave = true
1488
+ } = args;
1489
+ const client = useSocketClient();
1490
+ const normalizedRooms = React2.useMemo(
1491
+ () => rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms],
1492
+ [rooms]
1493
+ );
1494
+ const reportAsyncError = React2.useCallback(
1495
+ (phase, error) => {
1496
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
1497
+ console.warn(`[socket] useSocketConnection ${phase} failed`, error);
1498
+ }
1499
+ },
1500
+ []
1501
+ );
1502
+ React2.useEffect(() => {
1503
+ if (autoJoin && normalizedRooms.length > 0)
1504
+ void client.joinRooms(normalizedRooms, args.joinMeta).catch((error) => reportAsyncError("joinRooms", error));
1505
+ const unsubscribe = client.on(event, (payload, meta) => {
1506
+ onMessage(payload, meta);
1507
+ });
1508
+ return () => {
1509
+ unsubscribe();
1510
+ if (autoLeave && normalizedRooms.length > 0)
1511
+ void client.leaveRooms(normalizedRooms, args.leaveMeta).catch((error) => reportAsyncError("leaveRooms", error));
1512
+ if (onCleanup) onCleanup();
1513
+ };
1514
+ }, [
1515
+ client,
1516
+ event,
1517
+ onMessage,
1518
+ autoJoin,
1519
+ autoLeave,
1520
+ reportAsyncError,
1521
+ ...normalizedRooms
1522
+ ]);
1523
+ }
1524
+
1525
+ // src/sockets/socket.client.context.debug.ts
1526
+ function dbg(dbgOpts, e) {
1527
+ if (!dbgOpts?.logger) return;
1528
+ if (!dbgOpts[e.type]) return;
1529
+ try {
1530
+ dbgOpts.logger(e);
1531
+ } catch (error) {
1532
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
1533
+ console.warn("[socket] provider debug logger threw", error);
1534
+ }
1535
+ }
1536
+ }
1537
+ function isProbablySocket(value) {
1538
+ if (!value || typeof value !== "object") return false;
1539
+ const anyVal = value;
1540
+ const ctorName = anyVal.constructor?.name;
1541
+ if (ctorName === "Socket") return true;
1542
+ return ("connected" in anyVal || "recovered" in anyVal) && typeof anyVal.on === "function" && typeof anyVal.emit === "function";
1543
+ }
1544
+ function describeSocketLike(value) {
1545
+ if (!value) return null;
1546
+ const id = value.id ?? "unknown";
1547
+ const connected = value.connected ?? false;
1548
+ const recovered = typeof value.recovered === "boolean" ? ` recovered=${value.recovered}` : "";
1549
+ return `[Socket id=${id} connected=${connected}${recovered}]`;
1550
+ }
1551
+ function safeDescribeHookValue(value) {
1552
+ if (value == null) return value;
1553
+ const valueType = typeof value;
1554
+ if (valueType === "string" || valueType === "number" || valueType === "boolean") {
1555
+ return value;
1556
+ }
1557
+ if (valueType === "bigint" || valueType === "symbol") return String(value);
1558
+ if (valueType === "function")
1559
+ return `[function ${value.name || "anonymous"}]`;
1560
+ if (Array.isArray(value)) return `[array length=${value.length}]`;
1561
+ if (isProbablySocket(value)) return describeSocketLike(value);
1562
+ const ctorName = value.constructor?.name ?? "object";
1563
+ const keys = Object.keys(value);
1564
+ const keyPreview = keys.slice(0, 4).join(",");
1565
+ const suffix = keys.length > 4 ? ",\u2026" : "";
1566
+ return `[${ctorName} keys=${keyPreview}${suffix}]`;
1567
+ }
1568
+ function summarizeEvents(events) {
1569
+ if (!events || typeof events !== "object")
1570
+ return safeDescribeHookValue(events);
1571
+ const keys = Object.keys(events);
1572
+ if (!keys.length) return "[events empty]";
1573
+ const preview = keys.slice(0, 4).join(",");
1574
+ const suffix = keys.length > 4 ? ",\u2026" : "";
1575
+ return `[events count=${keys.length} keys=${preview}${suffix}]`;
1576
+ }
1577
+ function summarizeBaseOptions(options) {
1578
+ if (!options || typeof options !== "object")
1579
+ return safeDescribeHookValue(options);
1580
+ const obj = options;
1581
+ const keys = Object.keys(obj);
1582
+ if (!keys.length) return "[baseOptions empty]";
1583
+ const preview = keys.slice(0, 4).join(",");
1584
+ const suffix = keys.length > 4 ? ",\u2026" : "";
1585
+ const hasDebug = "debug" in obj;
1586
+ return `[baseOptions keys=${preview}${suffix} debug=${hasDebug}]`;
1587
+ }
1588
+ function summarizeMeta(meta, label) {
1589
+ if (meta == null) return null;
1590
+ if (typeof meta !== "object") return safeDescribeHookValue(meta);
1591
+ const keys = Object.keys(meta);
1592
+ if (!keys.length) return `[${label} empty]`;
1593
+ const preview = keys.slice(0, 4).join(",");
1594
+ const suffix = keys.length > 4 ? ",\u2026" : "";
1595
+ return `[${label} keys=${preview}${suffix}]`;
1596
+ }
1597
+ function createHookDebugEvent(prev, next, hook) {
1598
+ const reason = prev ? "change" : "init";
1599
+ const changed = Object.keys(next).reduce((acc, dependency) => {
1600
+ const prevValue = prev ? prev[dependency] : void 0;
1601
+ const nextValue = next[dependency];
1602
+ if (!prev || !Object.is(prevValue, nextValue)) {
1603
+ acc.push({
1604
+ dependency,
1605
+ previous: safeDescribeHookValue(prevValue),
1606
+ next: safeDescribeHookValue(nextValue)
1607
+ });
1608
+ }
1609
+ return acc;
1610
+ }, []);
1611
+ if (!changed.length) return null;
1612
+ return { type: "hook", phase: hook, reason, changes: changed };
1613
+ }
1614
+ function trackHookTrigger({
1615
+ ref,
1616
+ hook,
1617
+ providerDebug,
1618
+ snapshot
1619
+ }) {
1620
+ const prev = ref.current;
1621
+ ref.current = snapshot;
1622
+ if (!providerDebug?.logger || !providerDebug?.hook) return;
1623
+ const event = createHookDebugEvent(prev, snapshot, hook);
1624
+ if (event) dbg(providerDebug, event);
1625
+ }
1626
+
1298
1627
  // src/sockets/socket.client.sys.ts
1299
1628
  import { z } from "zod";
1300
1629
  var roomValueSchema = z.union([z.array(z.string()), z.string()]);
@@ -2098,168 +2427,6 @@ var SocketClient = class {
2098
2427
  }
2099
2428
  };
2100
2429
 
2101
- // src/sockets/socket.client.context.provider.tsx
2102
- import * as React3 from "react";
2103
-
2104
- // src/sockets/socket.client.context.client.ts
2105
- import * as React from "react";
2106
- var SocketCtx = React.createContext(null);
2107
- function useSocketClient() {
2108
- const ctx = React.useContext(SocketCtx);
2109
- if (!ctx)
2110
- throw new Error("SocketClient not found. Wrap with <SocketProvider>.");
2111
- return ctx;
2112
- }
2113
-
2114
- // src/sockets/socket.client.context.connection.ts
2115
- import * as React2 from "react";
2116
- function useSocketConnection(args) {
2117
- const {
2118
- event,
2119
- rooms,
2120
- onMessage,
2121
- onCleanup,
2122
- autoJoin = true,
2123
- autoLeave = true
2124
- } = args;
2125
- const client = useSocketClient();
2126
- const normalizedRooms = React2.useMemo(
2127
- () => rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms],
2128
- [rooms]
2129
- );
2130
- const reportAsyncError = React2.useCallback(
2131
- (phase, error) => {
2132
- if (typeof console !== "undefined" && typeof console.warn === "function") {
2133
- console.warn(`[socket] useSocketConnection ${phase} failed`, error);
2134
- }
2135
- },
2136
- []
2137
- );
2138
- React2.useEffect(() => {
2139
- if (autoJoin && normalizedRooms.length > 0)
2140
- void client.joinRooms(normalizedRooms, args.joinMeta).catch((error) => reportAsyncError("joinRooms", error));
2141
- const unsubscribe = client.on(event, (payload, meta) => {
2142
- onMessage(payload, meta);
2143
- });
2144
- return () => {
2145
- unsubscribe();
2146
- if (autoLeave && normalizedRooms.length > 0)
2147
- void client.leaveRooms(normalizedRooms, args.leaveMeta).catch((error) => reportAsyncError("leaveRooms", error));
2148
- if (onCleanup) onCleanup();
2149
- };
2150
- }, [
2151
- client,
2152
- event,
2153
- onMessage,
2154
- autoJoin,
2155
- autoLeave,
2156
- reportAsyncError,
2157
- ...normalizedRooms
2158
- ]);
2159
- }
2160
-
2161
- // src/sockets/socket.client.context.debug.ts
2162
- function dbg(dbgOpts, e) {
2163
- if (!dbgOpts?.logger) return;
2164
- if (!dbgOpts[e.type]) return;
2165
- try {
2166
- dbgOpts.logger(e);
2167
- } catch (error) {
2168
- if (typeof console !== "undefined" && typeof console.warn === "function") {
2169
- console.warn("[socket] provider debug logger threw", error);
2170
- }
2171
- }
2172
- }
2173
- function isProbablySocket(value) {
2174
- if (!value || typeof value !== "object") return false;
2175
- const anyVal = value;
2176
- const ctorName = anyVal.constructor?.name;
2177
- if (ctorName === "Socket") return true;
2178
- return ("connected" in anyVal || "recovered" in anyVal) && typeof anyVal.on === "function" && typeof anyVal.emit === "function";
2179
- }
2180
- function describeSocketLike(value) {
2181
- if (!value) return null;
2182
- const id = value.id ?? "unknown";
2183
- const connected = value.connected ?? false;
2184
- const recovered = typeof value.recovered === "boolean" ? ` recovered=${value.recovered}` : "";
2185
- return `[Socket id=${id} connected=${connected}${recovered}]`;
2186
- }
2187
- function safeDescribeHookValue(value) {
2188
- if (value == null) return value;
2189
- const valueType = typeof value;
2190
- if (valueType === "string" || valueType === "number" || valueType === "boolean") {
2191
- return value;
2192
- }
2193
- if (valueType === "bigint" || valueType === "symbol") return String(value);
2194
- if (valueType === "function")
2195
- return `[function ${value.name || "anonymous"}]`;
2196
- if (Array.isArray(value)) return `[array length=${value.length}]`;
2197
- if (isProbablySocket(value)) return describeSocketLike(value);
2198
- const ctorName = value.constructor?.name ?? "object";
2199
- const keys = Object.keys(value);
2200
- const keyPreview = keys.slice(0, 4).join(",");
2201
- const suffix = keys.length > 4 ? ",\u2026" : "";
2202
- return `[${ctorName} keys=${keyPreview}${suffix}]`;
2203
- }
2204
- function summarizeEvents(events) {
2205
- if (!events || typeof events !== "object")
2206
- return safeDescribeHookValue(events);
2207
- const keys = Object.keys(events);
2208
- if (!keys.length) return "[events empty]";
2209
- const preview = keys.slice(0, 4).join(",");
2210
- const suffix = keys.length > 4 ? ",\u2026" : "";
2211
- return `[events count=${keys.length} keys=${preview}${suffix}]`;
2212
- }
2213
- function summarizeBaseOptions(options) {
2214
- if (!options || typeof options !== "object")
2215
- return safeDescribeHookValue(options);
2216
- const obj = options;
2217
- const keys = Object.keys(obj);
2218
- if (!keys.length) return "[baseOptions empty]";
2219
- const preview = keys.slice(0, 4).join(",");
2220
- const suffix = keys.length > 4 ? ",\u2026" : "";
2221
- const hasDebug = "debug" in obj;
2222
- return `[baseOptions keys=${preview}${suffix} debug=${hasDebug}]`;
2223
- }
2224
- function summarizeMeta(meta, label) {
2225
- if (meta == null) return null;
2226
- if (typeof meta !== "object") return safeDescribeHookValue(meta);
2227
- const keys = Object.keys(meta);
2228
- if (!keys.length) return `[${label} empty]`;
2229
- const preview = keys.slice(0, 4).join(",");
2230
- const suffix = keys.length > 4 ? ",\u2026" : "";
2231
- return `[${label} keys=${preview}${suffix}]`;
2232
- }
2233
- function createHookDebugEvent(prev, next, hook) {
2234
- const reason = prev ? "change" : "init";
2235
- const changed = Object.keys(next).reduce((acc, dependency) => {
2236
- const prevValue = prev ? prev[dependency] : void 0;
2237
- const nextValue = next[dependency];
2238
- if (!prev || !Object.is(prevValue, nextValue)) {
2239
- acc.push({
2240
- dependency,
2241
- previous: safeDescribeHookValue(prevValue),
2242
- next: safeDescribeHookValue(nextValue)
2243
- });
2244
- }
2245
- return acc;
2246
- }, []);
2247
- if (!changed.length) return null;
2248
- return { type: "hook", phase: hook, reason, changes: changed };
2249
- }
2250
- function trackHookTrigger({
2251
- ref,
2252
- hook,
2253
- providerDebug,
2254
- snapshot
2255
- }) {
2256
- const prev = ref.current;
2257
- ref.current = snapshot;
2258
- if (!providerDebug?.logger || !providerDebug?.hook) return;
2259
- const event = createHookDebugEvent(prev, snapshot, hook);
2260
- if (event) dbg(providerDebug, event);
2261
- }
2262
-
2263
2430
  // src/sockets/socket.client.context.provider.tsx
2264
2431
  import { jsx } from "react/jsx-runtime";
2265
2432
  function buildSocketProvider(args) {
@@ -2402,7 +2569,7 @@ function SocketProvider(props) {
2402
2569
  }
2403
2570
 
2404
2571
  // src/sockets/socketedRoute/socket.client.helper.route.ts
2405
- import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef5, useState as useState2 } from "react";
2572
+ import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef6, useState as useState2 } from "react";
2406
2573
 
2407
2574
  // src/sockets/socketedRoute/socket.client.helper.debug.ts
2408
2575
  var objectReferenceIds = /* @__PURE__ */ new WeakMap();
@@ -2574,13 +2741,19 @@ function buildSocketedRoute(options) {
2574
2741
  const [roomState, setRoomState] = useState2(
2575
2742
  () => roomsFromData(endpointResult.data, toRooms)
2576
2743
  );
2577
- const renderCountRef = useRef5(0);
2578
- const clientReadyRef = useRef5(null);
2579
- const onReceiveEffectDebugRef = useRef5(null);
2580
- const deriveRoomsEffectDebugRef = useRef5(null);
2581
- const joinRoomsEffectDebugRef = useRef5(null);
2582
- const applySocketEffectDebugRef = useRef5(null);
2744
+ const renderCountRef = useRef6(0);
2745
+ const clientReadyRef = useRef6(null);
2746
+ const endpointDataRef = useRef6(
2747
+ endpointResult.data
2748
+ );
2749
+ const toRoomsRef = useRef6(toRooms);
2750
+ const onReceiveEffectDebugRef = useRef6(null);
2751
+ const deriveRoomsEffectDebugRef = useRef6(null);
2752
+ const joinRoomsEffectDebugRef = useRef6(null);
2753
+ const applySocketEffectDebugRef = useRef6(null);
2583
2754
  renderCountRef.current += 1;
2755
+ endpointDataRef.current = endpointResult.data;
2756
+ toRoomsRef.current = toRooms;
2584
2757
  const roomsKey = useMemo3(() => roomState.rooms.join("|"), [roomState.rooms]);
2585
2758
  const joinMetaKey = useMemo3(
2586
2759
  () => safeJsonKey(roomState.joinMeta ?? null),
@@ -2615,35 +2788,31 @@ function buildSocketedRoute(options) {
2615
2788
  phase: "endpoint_on_receive_effect",
2616
2789
  debug,
2617
2790
  snapshot: {
2618
- endpointResultRef: describeObjectReference(endpointResult),
2619
- endpointDataRef: describeObjectReference(endpointResult.data),
2620
- toRoomsRef: describeObjectReference(toRooms)
2791
+ onReceiveRef: describeObjectReference(endpointResult.onReceive)
2621
2792
  }
2622
2793
  });
2623
2794
  const unsubscribe = endpointResult.onReceive((data) => {
2624
2795
  setRoomState((prev) => {
2625
- const next = mergeRoomState(prev, toRooms(data));
2796
+ const next = mergeRoomState(prev, toRoomsRef.current(data));
2626
2797
  return roomStateEqual(prev, next) ? prev : next;
2627
2798
  });
2628
2799
  });
2629
2800
  return unsubscribe;
2630
- }, [endpointResult, toRooms, debug]);
2801
+ }, [endpointResult.onReceive]);
2631
2802
  useEffect3(() => {
2632
2803
  trackHookTrigger2({
2633
2804
  ref: deriveRoomsEffectDebugRef,
2634
2805
  phase: "derive_rooms_effect",
2635
2806
  debug,
2636
2807
  snapshot: {
2637
- endpointDataRef: describeObjectReference(endpointResult.data),
2808
+ argsKey,
2809
+ endpointDataRef: describeObjectReference(endpointDataRef.current),
2638
2810
  toRoomsRef: describeObjectReference(toRooms)
2639
2811
  }
2640
2812
  });
2641
- const next = roomsFromData(
2642
- endpointResult.data,
2643
- toRooms
2644
- );
2813
+ const next = roomsFromData(endpointDataRef.current, toRooms);
2645
2814
  setRoomState((prev) => roomStateEqual(prev, next) ? prev : next);
2646
- }, [endpointResult.data, toRooms, debug]);
2815
+ }, [argsKey, toRooms, debug]);
2647
2816
  useEffect3(() => {
2648
2817
  trackHookTrigger2({
2649
2818
  ref: joinRoomsEffectDebugRef,