@emeryld/rrroutes-client 2.6.6 → 2.6.7
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 +192 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +185 -18
- 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/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) {
|
|
@@ -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,12 +2741,12 @@ 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 onReceiveEffectDebugRef =
|
|
2580
|
-
const deriveRoomsEffectDebugRef =
|
|
2581
|
-
const joinRoomsEffectDebugRef =
|
|
2582
|
-
const applySocketEffectDebugRef =
|
|
2744
|
+
const renderCountRef = useRef6(0);
|
|
2745
|
+
const clientReadyRef = useRef6(null);
|
|
2746
|
+
const onReceiveEffectDebugRef = useRef6(null);
|
|
2747
|
+
const deriveRoomsEffectDebugRef = useRef6(null);
|
|
2748
|
+
const joinRoomsEffectDebugRef = useRef6(null);
|
|
2749
|
+
const applySocketEffectDebugRef = useRef6(null);
|
|
2583
2750
|
renderCountRef.current += 1;
|
|
2584
2751
|
const roomsKey = useMemo3(() => roomState.rooms.join("|"), [roomState.rooms]);
|
|
2585
2752
|
const joinMetaKey = useMemo3(
|