@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/README.md +49 -3
- package/dist/index.cjs +367 -200
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +360 -191
- package/dist/index.mjs.map +1 -1
- package/dist/routesV3.client.d.ts +1 -1
- package/dist/routesV3.client.types.d.ts +76 -0
- package/dist/sockets/socket.client.context.provider.d.ts +14 -0
- package/dist/sockets/socket.client.core.d.ts +1 -1
- package/dist/sockets/socket.client.index.d.ts +2 -1
- package/dist/sockets/socketedRoute/socket.client.helper.route.d.ts +2 -3
- package/package.json +1 -1
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
|
-
|
|
1216
|
+
built = buildInfiniteGetLeaf(
|
|
1197
1217
|
leaf,
|
|
1198
1218
|
rqOpts,
|
|
1199
1219
|
env
|
|
1200
1220
|
);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
|
|
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
|
-
|
|
1210
|
-
leaf,
|
|
1211
|
-
|
|
1212
|
-
|
|
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
|
|
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 =
|
|
2578
|
-
const clientReadyRef =
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
const
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
}, [
|
|
2815
|
+
}, [argsKey, toRooms, debug]);
|
|
2647
2816
|
useEffect3(() => {
|
|
2648
2817
|
trackHookTrigger2({
|
|
2649
2818
|
ref: joinRoomsEffectDebugRef,
|