@emeryld/rrroutes-client 2.7.2 → 2.7.4
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 +11 -6
- package/dist/index.cjs +79 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +79 -18
- package/dist/index.mjs.map +1 -1
- package/dist/routesV3.client.shared.d.ts +5 -0
- package/dist/sockets/socketedRoute/socket.client.helper.rooms.d.ts +9 -2
- package/dist/sockets/socketedRoute/socket.client.helper.route.d.ts +9 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -468,20 +468,21 @@ import { buildSocketedRoute } from '@emeryld/rrroutes-client';
|
|
|
468
468
|
import { useSocketClient } from './socketProvider';
|
|
469
469
|
|
|
470
470
|
const listRooms = client.build(registry.byKey['GET /v1/rooms'], { staleTime: 120_000 });
|
|
471
|
+
const useAppSocketContext = () => ({ workspaceId: 'acme' });
|
|
471
472
|
|
|
472
473
|
const socketedRooms = buildSocketedRoute({
|
|
473
474
|
built: listRooms,
|
|
474
|
-
|
|
475
|
-
|
|
475
|
+
useContext: useAppSocketContext, // optional app-level context for hooks
|
|
476
|
+
toRooms: ({ data, meta }) => ({
|
|
477
|
+
rooms: data.items.map((r) => `${meta?.appContext?.workspaceId}:${r.id}`), // derive rooms from data (feeds supported)
|
|
476
478
|
joinMeta: { source: 'rooms:list' },
|
|
477
479
|
leaveMeta: { source: 'rooms:list' },
|
|
478
480
|
}),
|
|
479
481
|
useSocketClient,
|
|
480
482
|
applySocket: {
|
|
481
|
-
'chat:message': (prev, payload, meta) => {
|
|
483
|
+
'chat:message': ({ prev, payload, args, meta }) => {
|
|
482
484
|
if (!prev) return null; // explicit no-op update
|
|
483
|
-
|
|
484
|
-
console.debug('socket patch args', args);
|
|
485
|
+
console.debug('socket patch args', args, meta.appContext?.workspaceId, meta.ctx?.socketId);
|
|
485
486
|
// Example: bump unread count in cache
|
|
486
487
|
const apply = (items: any[]) =>
|
|
487
488
|
items.map((room) =>
|
|
@@ -505,7 +506,11 @@ function RoomList() {
|
|
|
505
506
|
}
|
|
506
507
|
```
|
|
507
508
|
|
|
508
|
-
`buildSocketedRoute(...)` returns a built endpoint object with `useEndpoint()` plus the original built helpers.
|
|
509
|
+
`buildSocketedRoute(...)` returns a built endpoint object with `useEndpoint()` plus the original built helpers.
|
|
510
|
+
|
|
511
|
+
- `toRooms` receives `{ data, args, meta }` where `meta.appContext` comes from `useContext` (if provided).
|
|
512
|
+
- `applySocket` handlers receive `{ prev, payload, args, meta }`, where `meta` contains `envelope?`, `ctx?`, and `appContext?`.
|
|
513
|
+
- Return `null` from `applySocket` to skip cache updates.
|
|
509
514
|
|
|
510
515
|
---
|
|
511
516
|
|
package/dist/index.cjs
CHANGED
|
@@ -300,6 +300,16 @@ function buildUrl(leaf, baseUrl, params, query) {
|
|
|
300
300
|
const url = `${baseUrl ?? ""}${path}${toSearchString(normalizedQuery)}`;
|
|
301
301
|
return { url, normalizedQuery, normalizedParams };
|
|
302
302
|
}
|
|
303
|
+
function areEndpointArgsComplete(leaf, args) {
|
|
304
|
+
const params = args?.params;
|
|
305
|
+
const query = args?.query;
|
|
306
|
+
try {
|
|
307
|
+
buildUrl(leaf, "", params, query);
|
|
308
|
+
return true;
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
303
313
|
function isBlobLike(value) {
|
|
304
314
|
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
305
315
|
}
|
|
@@ -643,6 +653,7 @@ function buildGetLeaf(leaf, rqOpts, env) {
|
|
|
643
653
|
const useEndpoint = (...useArgs) => {
|
|
644
654
|
const args = expectsArgs ? useArgs[0] : void 0;
|
|
645
655
|
const useEndpointOptions = expectsArgs ? useArgs[1] : useArgs[0];
|
|
656
|
+
const hasCompleteArgs = !expectsArgs || areEndpointArgsComplete(leaf, args);
|
|
646
657
|
const tuple = toArgsTuple(args);
|
|
647
658
|
const queryKeys = getQueryKeys(...tuple);
|
|
648
659
|
emit({
|
|
@@ -657,6 +668,8 @@ function buildGetLeaf(leaf, rqOpts, env) {
|
|
|
657
668
|
...buildQueryOptions,
|
|
658
669
|
...runtimeQueryOptions
|
|
659
670
|
};
|
|
671
|
+
const mergedEnabled = mergedQueryOptions.enabled;
|
|
672
|
+
const guardedEnabled = hasCompleteArgs && (typeof mergedEnabled === "undefined" ? true : mergedEnabled);
|
|
660
673
|
const listenersRef = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
|
|
661
674
|
const notifyOnReceive = (0, import_react2.useCallback)((data) => {
|
|
662
675
|
buildOnReceive2?.(data);
|
|
@@ -675,11 +688,17 @@ function buildGetLeaf(leaf, rqOpts, env) {
|
|
|
675
688
|
const queryResult = (0, import_react_query2.useQuery)(
|
|
676
689
|
{
|
|
677
690
|
...mergedQueryOptions,
|
|
691
|
+
enabled: guardedEnabled,
|
|
678
692
|
queryKey: getQueryKeys(...tuple),
|
|
679
693
|
placeholderData: mergedQueryOptions.placeholderData ?? import_react_query2.keepPreviousData,
|
|
680
|
-
queryFn: () =>
|
|
681
|
-
|
|
682
|
-
|
|
694
|
+
queryFn: () => {
|
|
695
|
+
if (!hasCompleteArgs) {
|
|
696
|
+
return Promise.resolve(void 0);
|
|
697
|
+
}
|
|
698
|
+
return fetchEndpoint(tuple, {
|
|
699
|
+
onReceive: notifyOnReceive
|
|
700
|
+
});
|
|
701
|
+
}
|
|
683
702
|
},
|
|
684
703
|
queryClient
|
|
685
704
|
);
|
|
@@ -923,6 +942,7 @@ function buildInfiniteGetLeaf(leaf, rqOpts, env) {
|
|
|
923
942
|
const useEndpoint = (...useArgs) => {
|
|
924
943
|
const args = expectsArgs ? useArgs[0] : void 0;
|
|
925
944
|
const useEndpointOptions = expectsArgs ? useArgs[1] : useArgs[0];
|
|
945
|
+
const hasCompleteArgs = !expectsArgs || areEndpointArgsComplete(leaf, args);
|
|
926
946
|
const tuple = toArgsTuple(args);
|
|
927
947
|
const queryKeys = getQueryKeys(...tuple);
|
|
928
948
|
emit({
|
|
@@ -940,6 +960,8 @@ function buildInfiniteGetLeaf(leaf, rqOpts, env) {
|
|
|
940
960
|
...buildInfiniteQueryOptions,
|
|
941
961
|
...runtimeInfiniteQueryOptions
|
|
942
962
|
};
|
|
963
|
+
const mergedEnabled = mergedInfiniteQueryOptions.enabled;
|
|
964
|
+
const guardedEnabled = hasCompleteArgs && (typeof mergedEnabled === "undefined" ? true : mergedEnabled);
|
|
943
965
|
const listenersRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
|
|
944
966
|
const notifyOnReceive = (0, import_react3.useCallback)((data) => {
|
|
945
967
|
buildOnReceive2?.(data);
|
|
@@ -955,20 +977,22 @@ function buildInfiniteGetLeaf(leaf, rqOpts, env) {
|
|
|
955
977
|
},
|
|
956
978
|
[]
|
|
957
979
|
);
|
|
958
|
-
const { normalizedQuery, normalizedParams } = buildUrl(
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
query
|
|
963
|
-
);
|
|
980
|
+
const { normalizedQuery, normalizedParams } = hasCompleteArgs ? buildUrl({ ...leaf, cfg: leafCfg }, baseUrl, params, query) : {
|
|
981
|
+
normalizedQuery: query ?? {},
|
|
982
|
+
normalizedParams: params ?? {}
|
|
983
|
+
};
|
|
964
984
|
const queryResult = (0, import_react_query3.useInfiniteQuery)(
|
|
965
985
|
{
|
|
966
986
|
...mergedInfiniteQueryOptions,
|
|
987
|
+
enabled: guardedEnabled,
|
|
967
988
|
placeholderData: mergedInfiniteQueryOptions.placeholderData ?? import_react_query3.keepPreviousData,
|
|
968
989
|
initialPageParam: feedInitialPageParam,
|
|
969
990
|
getNextPageParam: (lastPage) => cursorFromPage(lastPage),
|
|
970
991
|
queryKey: queryKeys,
|
|
971
992
|
queryFn: ({ pageParam }) => {
|
|
993
|
+
if (!hasCompleteArgs) {
|
|
994
|
+
return Promise.resolve(void 0);
|
|
995
|
+
}
|
|
972
996
|
if (!effectiveSplitPageSize) {
|
|
973
997
|
const pageQuery = {
|
|
974
998
|
...normalizedQuery,
|
|
@@ -2752,12 +2776,15 @@ function mergeRoomState(prev, toRoomsResult) {
|
|
|
2752
2776
|
leaveMeta: toRoomsResult.leaveMeta ?? prev.leaveMeta
|
|
2753
2777
|
};
|
|
2754
2778
|
}
|
|
2755
|
-
function roomsFromData(data, args, toRooms) {
|
|
2779
|
+
function roomsFromData(data, args, toRooms, meta) {
|
|
2756
2780
|
if (data == null) return { rooms: [] };
|
|
2757
2781
|
let state = { rooms: [] };
|
|
2758
2782
|
const add = (input) => {
|
|
2759
2783
|
const mergeForValue = (value) => {
|
|
2760
|
-
state = mergeRoomState(
|
|
2784
|
+
state = mergeRoomState(
|
|
2785
|
+
state,
|
|
2786
|
+
toRooms({ data: value, args, meta })
|
|
2787
|
+
);
|
|
2761
2788
|
};
|
|
2762
2789
|
if (Array.isArray(input)) {
|
|
2763
2790
|
input.forEach((entry) => mergeForValue(entry));
|
|
@@ -2792,8 +2819,21 @@ function parseUseEndpointArgs(useArgs) {
|
|
|
2792
2819
|
const endpointArgsTuple = typeof endpointArgs === "undefined" ? [] : [endpointArgs];
|
|
2793
2820
|
return { endpointArgs, endpointArgsTuple };
|
|
2794
2821
|
}
|
|
2822
|
+
function useDefaultSocketedRouteContext() {
|
|
2823
|
+
return void 0;
|
|
2824
|
+
}
|
|
2825
|
+
function createToRoomsMeta(appContext) {
|
|
2826
|
+
return { appContext };
|
|
2827
|
+
}
|
|
2795
2828
|
function buildSocketedRoute(options) {
|
|
2796
|
-
const {
|
|
2829
|
+
const {
|
|
2830
|
+
built,
|
|
2831
|
+
toRooms,
|
|
2832
|
+
applySocket,
|
|
2833
|
+
useSocketClient: useSocketClient2,
|
|
2834
|
+
useContext: useRouteContext = useDefaultSocketedRouteContext,
|
|
2835
|
+
debug
|
|
2836
|
+
} = options;
|
|
2797
2837
|
const { useEndpoint: useInnerEndpoint, ...rest } = built;
|
|
2798
2838
|
const useEndpoint = (...useArgs) => {
|
|
2799
2839
|
const client = useSocketClient2();
|
|
@@ -2801,6 +2841,11 @@ function buildSocketedRoute(options) {
|
|
|
2801
2841
|
const endpointResult = useInnerEndpoint(
|
|
2802
2842
|
...useArgs
|
|
2803
2843
|
);
|
|
2844
|
+
const appContext = useRouteContext();
|
|
2845
|
+
const toRoomsMeta = (0, import_react5.useMemo)(
|
|
2846
|
+
() => createToRoomsMeta(appContext),
|
|
2847
|
+
[appContext]
|
|
2848
|
+
);
|
|
2804
2849
|
const { endpointArgs, endpointArgsTuple } = parseUseEndpointArgs(useArgs);
|
|
2805
2850
|
const argsKey = (0, import_react5.useMemo)(
|
|
2806
2851
|
() => safeJsonKey(endpointArgs ?? null),
|
|
@@ -2810,7 +2855,8 @@ function buildSocketedRoute(options) {
|
|
|
2810
2855
|
() => roomsFromData(
|
|
2811
2856
|
endpointResult.data,
|
|
2812
2857
|
endpointArgs,
|
|
2813
|
-
toRooms
|
|
2858
|
+
toRooms,
|
|
2859
|
+
toRoomsMeta
|
|
2814
2860
|
)
|
|
2815
2861
|
);
|
|
2816
2862
|
const renderCountRef = (0, import_react5.useRef)(0);
|
|
@@ -2819,6 +2865,7 @@ function buildSocketedRoute(options) {
|
|
|
2819
2865
|
endpointResult.data
|
|
2820
2866
|
);
|
|
2821
2867
|
const toRoomsRef = (0, import_react5.useRef)(toRooms);
|
|
2868
|
+
const toRoomsMetaRef = (0, import_react5.useRef)(toRoomsMeta);
|
|
2822
2869
|
const onReceiveEffectDebugRef = (0, import_react5.useRef)(null);
|
|
2823
2870
|
const deriveRoomsEffectDebugRef = (0, import_react5.useRef)(null);
|
|
2824
2871
|
const joinRoomsEffectDebugRef = (0, import_react5.useRef)(null);
|
|
@@ -2826,6 +2873,7 @@ function buildSocketedRoute(options) {
|
|
|
2826
2873
|
renderCountRef.current += 1;
|
|
2827
2874
|
endpointDataRef.current = endpointResult.data;
|
|
2828
2875
|
toRoomsRef.current = toRooms;
|
|
2876
|
+
toRoomsMetaRef.current = toRoomsMeta;
|
|
2829
2877
|
const roomsKey = (0, import_react5.useMemo)(() => roomState.rooms.join("|"), [roomState.rooms]);
|
|
2830
2878
|
const joinMetaKey = (0, import_react5.useMemo)(
|
|
2831
2879
|
() => safeJsonKey(roomState.joinMeta ?? null),
|
|
@@ -2867,7 +2915,11 @@ function buildSocketedRoute(options) {
|
|
|
2867
2915
|
setRoomState((prev) => {
|
|
2868
2916
|
const next = mergeRoomState(
|
|
2869
2917
|
prev,
|
|
2870
|
-
toRoomsRef.current(
|
|
2918
|
+
toRoomsRef.current({
|
|
2919
|
+
data,
|
|
2920
|
+
args: endpointArgs,
|
|
2921
|
+
meta: toRoomsMetaRef.current
|
|
2922
|
+
})
|
|
2871
2923
|
);
|
|
2872
2924
|
return roomStateEqual(prev, next) ? prev : next;
|
|
2873
2925
|
});
|
|
@@ -2885,9 +2937,14 @@ function buildSocketedRoute(options) {
|
|
|
2885
2937
|
toRoomsRef: describeObjectReference(toRooms)
|
|
2886
2938
|
}
|
|
2887
2939
|
});
|
|
2888
|
-
const next = roomsFromData(
|
|
2940
|
+
const next = roomsFromData(
|
|
2941
|
+
endpointDataRef.current,
|
|
2942
|
+
endpointArgs,
|
|
2943
|
+
toRooms,
|
|
2944
|
+
toRoomsMeta
|
|
2945
|
+
);
|
|
2889
2946
|
setRoomState((prev) => roomStateEqual(prev, next) ? prev : next);
|
|
2890
|
-
}, [argsKey, toRooms, debug]);
|
|
2947
|
+
}, [argsKey, toRooms, toRoomsMeta, debug]);
|
|
2891
2948
|
(0, import_react5.useEffect)(() => {
|
|
2892
2949
|
trackHookTrigger2({
|
|
2893
2950
|
ref: joinRoomsEffectDebugRef,
|
|
@@ -3005,7 +3062,10 @@ function buildSocketedRoute(options) {
|
|
|
3005
3062
|
prev,
|
|
3006
3063
|
payload: nextUpdate.payload,
|
|
3007
3064
|
args: endpointArgs,
|
|
3008
|
-
meta:
|
|
3065
|
+
meta: {
|
|
3066
|
+
...nextUpdate.meta ?? {},
|
|
3067
|
+
appContext: toRoomsMetaRef.current.appContext
|
|
3068
|
+
}
|
|
3009
3069
|
});
|
|
3010
3070
|
if (next === null) return prev;
|
|
3011
3071
|
if (shouldWarnSocketMutationGuard() && isSameObjectReference(prev, next) && !sameRefWarnedEvents.has(nextUpdate.event)) {
|
|
@@ -3017,7 +3077,8 @@ function buildSocketedRoute(options) {
|
|
|
3017
3077
|
const nextRoomState = roomsFromData(
|
|
3018
3078
|
next,
|
|
3019
3079
|
endpointArgs,
|
|
3020
|
-
toRooms
|
|
3080
|
+
toRooms,
|
|
3081
|
+
toRoomsMetaRef.current
|
|
3021
3082
|
);
|
|
3022
3083
|
setRoomState(
|
|
3023
3084
|
(prevRoomState) => roomStateEqual(prevRoomState, nextRoomState) ? prevRoomState : nextRoomState
|