@emeryld/rrroutes-client 2.2.14 → 2.2.16

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.
@@ -1,5 +1,5 @@
1
+ import type { AnyLeafLowProfile, HttpMethod, InferBody, InferOutput, InferParams, InferQuery, Prettify } from '@emeryld/rrroutes-contract';
1
2
  import type { InfiniteData, QueryClient, QueryKey, UseInfiniteQueryOptions, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
2
- import type { AnyLeaf, HttpMethod, InferBody, InferOutput, InferParams, InferQuery, Prettify } from '@emeryld/rrroutes-contract';
3
3
  /** Helper type used when setting React Query cache data. */
4
4
  export type Updater<T> = T | ((prev: T | undefined) => T | undefined) | undefined;
5
5
  /** Cursor string extracted from paginated endpoints. */
@@ -97,21 +97,20 @@ export type RouteClientOptions<Names extends string = string> = {
97
97
  */
98
98
  environment?: RouteClientEnvironment;
99
99
  };
100
- type OutputOf<L extends AnyLeaf> = InferOutput<L>;
101
- type ParamsOf<L extends AnyLeaf> = InferParams<L>;
102
- type QueryOf<L extends AnyLeaf> = InferQuery<L>;
103
- type BodyOf<L extends AnyLeaf> = InferBody<L>;
104
- type OnReceive<L extends AnyLeaf> = (data: OutputOf<L>) => void;
105
- type OnReceiveRegistrar<L extends AnyLeaf> = (listener: OnReceive<L>) => () => void;
106
- type UseEndpointResult<L extends AnyLeaf, Result> = Result & {
100
+ type OnReceive<L extends AnyLeafLowProfile> = (data: InferOutput<L>) => void;
101
+ type OnReceiveRegistrar<L extends AnyLeafLowProfile> = (listener: OnReceive<L>) => () => void;
102
+ type UseEndpointResult<L extends AnyLeafLowProfile, Result> = Result & {
107
103
  onReceive: OnReceiveRegistrar<L>;
108
104
  };
109
105
  /** Variadic args consumed by the direct fetch helper: optional args + body. */
110
- export type MutationFetchArgs<L extends AnyLeaf> = Prettify<[...ArgsTuple<L>, BodyOf<L>]>;
106
+ export type MutationFetchArgs<L extends AnyLeafLowProfile> = Prettify<[
107
+ ...ArgsTuple<L>,
108
+ InferBody<L>
109
+ ]>;
111
110
  /** Signature for the fetch helper returned by mutation builds. */
112
- export type MutationFetcher<L extends AnyLeaf> = (...args: MutationFetchArgs<L>) => Promise<OutputOf<L>>;
111
+ export type MutationFetcher<L extends AnyLeafLowProfile> = (...args: MutationFetchArgs<L>) => Promise<InferOutput<L>>;
113
112
  /** Fetch args for GET endpoints (optionally include a body when a schema exists). */
114
- type QueryFetchArgs<L extends AnyLeaf> = BodyOf<L> extends never ? ArgsTuple<L> : Prettify<ArgsTuple<L> | [...ArgsTuple<L>, BodyOf<L>]>;
113
+ type QueryFetchArgs<L extends AnyLeafLowProfile> = InferBody<L> extends never ? ArgsTuple<L> : Prettify<ArgsTuple<L> | [...ArgsTuple<L>, InferBody<L>]>;
115
114
  /** Optional metadata provided when building a helper (used for debug filtering). */
116
115
  export type BuildMeta<Names extends string = string> = {
117
116
  /**
@@ -121,57 +120,60 @@ export type BuildMeta<Names extends string = string> = {
121
120
  name?: Names;
122
121
  };
123
122
  /** Object shape the user passes to hooks and helpers (params/query are optional). */
124
- export type ArgsFor<L extends AnyLeaf> = Prettify<(ParamsOf<L> extends never ? {} : {
125
- params: ParamsOf<L>;
126
- }) & (QueryOf<L> extends never ? {} : {
127
- query: QueryOf<L>;
123
+ export type ArgsFor<L extends AnyLeafLowProfile> = Prettify<(InferParams<L> extends never ? {} : {
124
+ params: InferParams<L>;
125
+ }) & (InferQuery<L> extends never ? {} : {
126
+ query: InferQuery<L>;
128
127
  })>;
129
128
  /** Variadic tuple representation that omits the argument entirely when not needed. */
130
- export type ArgsTuple<L extends AnyLeaf> = keyof ArgsFor<L> extends never ? [] : [args: ArgsFor<L>];
129
+ export type ArgsTuple<L extends AnyLeafLowProfile> = keyof ArgsFor<L> extends never ? [] : [args: ArgsFor<L>];
131
130
  /** Cache data shape for setData(...) */
132
- export type DataShape<L extends AnyLeaf> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? InfiniteData<OutputOf<L>> : OutputOf<L> : OutputOf<L>;
133
- type ArgsFromTuple<L extends AnyLeaf, T extends ArgsTuple<L>> = T extends [infer A] ? A : undefined;
134
- type ParamsFromArgs<L extends AnyLeaf, T extends ArgsTuple<L>> = ArgsFromTuple<L, T> extends {
131
+ export type DataShape<L extends AnyLeafLowProfile> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? InfiniteData<InferOutput<L>> : InferOutput<L> : InferOutput<L>;
132
+ type ArgsFromTuple<L extends AnyLeafLowProfile, T extends ArgsTuple<L>> = T extends [infer A] ? A : undefined;
133
+ type ParamsFromArgs<L extends AnyLeafLowProfile, T extends ArgsTuple<L>> = ArgsFromTuple<L, T> extends {
135
134
  params: infer P;
136
135
  } ? P : undefined;
137
- type SetDataArgs<L extends AnyLeaf> = Prettify<[updater: Updater<DataShape<L>>, ...ArgsTuple<L>]>;
138
- type QueryFromArgs<L extends AnyLeaf, T extends ArgsTuple<L>> = ArgsFromTuple<L, T> extends {
136
+ type SetDataArgs<L extends AnyLeafLowProfile> = Prettify<[
137
+ updater: Updater<DataShape<L>>,
138
+ ...ArgsTuple<L>
139
+ ]>;
140
+ type QueryFromArgs<L extends AnyLeafLowProfile, T extends ArgsTuple<L>> = ArgsFromTuple<L, T> extends {
139
141
  query: infer Q;
140
142
  } ? Q : undefined;
141
143
  /** Typed query key array derived from the leaf plus the specific args passed in. */
142
144
  type SplitUrl<L extends string> = L extends `/${infer A}` ? SplitUrl<A> : L extends `${infer A}/${infer B}` ? [A, ...SplitUrl<B>] : [L];
143
- type MapParams<P extends any[], Params> = P extends [infer A, ...infer Rest] ? A extends `:${infer Key}` ? [Params extends Record<Key, infer V> ? string extends V ? A : V : A, ...MapParams<Rest, Params>] : [
144
- A,
145
+ type MapParams<P extends any[], Params> = P extends [infer A, ...infer Rest] ? A extends `:${infer Key}` ? [
146
+ Params extends Record<Key, infer V> ? (string extends V ? A : V) : A,
145
147
  ...MapParams<Rest, Params>
146
- ] : [];
147
- export type QueryKeysFor<L extends AnyLeaf, T extends ArgsTuple<L>> = Prettify<readonly [
148
+ ] : [A, ...MapParams<Rest, Params>] : [];
149
+ export type QueryKeysFor<L extends AnyLeafLowProfile, T extends ArgsTuple<L>> = Prettify<readonly [
148
150
  L['method'],
149
151
  ...MapParams<SplitUrl<L['path']>, ParamsFromArgs<L, T>>,
150
152
  QueryFromArgs<L, T> extends undefined ? {} : QueryFromArgs<L, T>
151
153
  ]>;
152
154
  /** React Query build options specialized for a plain GET leaf. */
153
- export type QueryBuildOptionsFor<L extends AnyLeaf> = Omit<UseQueryOptions<OutputOf<L>, unknown, OutputOf<L>, QueryKey>, 'queryKey' | 'queryFn'> & {
155
+ export type QueryBuildOptionsFor<L extends AnyLeafLowProfile> = Omit<UseQueryOptions<InferOutput<L>, unknown, InferOutput<L>, QueryKey>, 'queryKey' | 'queryFn'> & {
154
156
  /** Hook invoked after a successful fetch + validation. */
155
157
  onReceive?: OnReceive<L>;
156
158
  };
157
159
  /** Build options for feed-style GET leaves (`cfg.feed === true`). */
158
- export type InfiniteBuildOptionsFor<L extends AnyLeaf> = Omit<UseInfiniteQueryOptions<OutputOf<L>, unknown, InfiniteData<OutputOf<L>>, QueryKey, Cursor>, 'queryKey' | 'queryFn' | 'initialPageParam' | 'getNextPageParam'> & {
160
+ export type InfiniteBuildOptionsFor<L extends AnyLeafLowProfile> = Omit<UseInfiniteQueryOptions<InferOutput<L>, unknown, InfiniteData<InferOutput<L>>, QueryKey, Cursor>, 'queryKey' | 'queryFn' | 'initialPageParam' | 'getNextPageParam'> & {
159
161
  /** Hook invoked after a successful fetch + validation. */
160
162
  onReceive?: OnReceive<L>;
161
163
  };
162
164
  /** Build options for mutation leaves (non-GET). */
163
- export type MutationBuildOptionsFor<L extends AnyLeaf> = Omit<UseMutationOptions<OutputOf<L>, unknown, BodyOf<L>, unknown>, 'mutationFn' | 'mutationKey'> & {
165
+ export type MutationBuildOptionsFor<L extends AnyLeafLowProfile> = Omit<UseMutationOptions<InferOutput<L>, unknown, InferBody<L>, unknown>, 'mutationFn' | 'mutationKey'> & {
164
166
  /** Hook invoked after a successful fetch + validation. */
165
167
  onReceive?: OnReceive<L>;
166
168
  };
167
169
  /** Build options narrowed to the method/feed shape of the leaf. */
168
- export type BuildOptionsFor<L extends AnyLeaf> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? InfiniteBuildOptionsFor<L> : QueryBuildOptionsFor<L> : MutationBuildOptionsFor<L>;
169
- export type UseEndpointArgs<L extends AnyLeaf> = ArgsTuple<L>;
170
- export type QueryUseEndpointResultFor<L extends AnyLeaf> = UseEndpointResult<L, UseQueryResult<OutputOf<L>, unknown>>;
171
- export type InfiniteUseEndpointResultFor<L extends AnyLeaf> = UseEndpointResult<L, UseInfiniteQueryResult<InfiniteData<OutputOf<L>>, unknown>>;
172
- export type MutationUseEndpointResultFor<L extends AnyLeaf> = UseEndpointResult<L, UseMutationResult<OutputOf<L>, unknown, BodyOf<L>, unknown>>;
170
+ export type BuildOptionsFor<L extends AnyLeafLowProfile> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? InfiniteBuildOptionsFor<L> : QueryBuildOptionsFor<L> : MutationBuildOptionsFor<L>;
171
+ export type UseEndpointArgs<L extends AnyLeafLowProfile> = ArgsTuple<L>;
172
+ export type QueryUseEndpointResultFor<L extends AnyLeafLowProfile> = UseEndpointResult<L, UseQueryResult<InferOutput<L>, unknown>>;
173
+ export type InfiniteUseEndpointResultFor<L extends AnyLeafLowProfile> = UseEndpointResult<L, UseInfiniteQueryResult<InfiniteData<InferOutput<L>>, unknown>>;
174
+ export type MutationUseEndpointResultFor<L extends AnyLeafLowProfile> = UseEndpointResult<L, UseMutationResult<InferOutput<L>, unknown, InferBody<L>, unknown>>;
173
175
  /** Shared capabilities exposed by every built endpoint helper. */
174
- export type BuiltCommon<L extends AnyLeaf> = {
176
+ export type BuiltCommon<L extends AnyLeafLowProfile> = {
175
177
  /**
176
178
  * Deterministic key (infinite keys omit the cursor by design).
177
179
  * @param args Optional params/query tuple for the leaf.
@@ -191,7 +193,7 @@ export type BuiltCommon<L extends AnyLeaf> = {
191
193
  setData: (...args: SetDataArgs<L>) => DataShape<L> | undefined;
192
194
  };
193
195
  /** Hook+helpers for a standard GET endpoint. */
194
- export type BuiltQuery<L extends AnyLeaf> = BuiltCommon<L> & {
196
+ export type BuiltQuery<L extends AnyLeafLowProfile> = BuiltCommon<L> & {
195
197
  /**
196
198
  * React hook bound to the GET leaf.
197
199
  * @param args Optional params/query tuple for the leaf.
@@ -201,10 +203,10 @@ export type BuiltQuery<L extends AnyLeaf> = BuiltCommon<L> & {
201
203
  * Direct fetch helper mirroring the query hook without touching the cache.
202
204
  * @param args Optional params/query tuple for the leaf.
203
205
  */
204
- fetch: (...args: QueryFetchArgs<L>) => Promise<OutputOf<L>>;
206
+ fetch: (...args: QueryFetchArgs<L>) => Promise<InferOutput<L>>;
205
207
  };
206
208
  /** Hook+helpers for a cursor-paginated GET endpoint. */
207
- export type BuiltInfinite<L extends AnyLeaf> = BuiltCommon<L> & {
209
+ export type BuiltInfinite<L extends AnyLeafLowProfile> = BuiltCommon<L> & {
208
210
  /**
209
211
  * React hook bound to an infinite GET leaf.
210
212
  * @param args Optional params/query tuple for the leaf.
@@ -214,10 +216,10 @@ export type BuiltInfinite<L extends AnyLeaf> = BuiltCommon<L> & {
214
216
  * Direct fetch helper for a single page of the feed (pass cursor in query args).
215
217
  * @param args Optional params/query tuple for the leaf.
216
218
  */
217
- fetch: (...args: QueryFetchArgs<L>) => Promise<OutputOf<L>>;
219
+ fetch: (...args: QueryFetchArgs<L>) => Promise<InferOutput<L>>;
218
220
  };
219
221
  /** Hook+helpers for non-GET endpoints (mutations). */
220
- export type BuiltMutation<L extends AnyLeaf> = BuiltCommon<L> & {
222
+ export type BuiltMutation<L extends AnyLeafLowProfile> = BuiltCommon<L> & {
221
223
  /**
222
224
  * React hook bound to a mutation leaf.
223
225
  * @param args Optional params/query tuple for the leaf.
@@ -230,7 +232,7 @@ export type BuiltMutation<L extends AnyLeaf> = BuiltCommon<L> & {
230
232
  fetch: MutationFetcher<L>;
231
233
  };
232
234
  /** Type-safe union that resolves to the correct built helper for a leaf. */
233
- export type BuiltForLeaf<L extends AnyLeaf> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L> : BuiltMutation<L>;
235
+ export type BuiltForLeaf<L extends AnyLeafLowProfile> = L['method'] extends 'get' ? L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L> : BuiltMutation<L>;
234
236
  /** Public surface returned by `createRouteClient`. */
235
237
  export type RouteClient<Names extends string = string> = {
236
238
  /**
@@ -240,15 +242,56 @@ export type RouteClient<Names extends string = string> = {
240
242
  */
241
243
  invalidate: (prefix: string[], exact?: boolean) => Promise<void>;
242
244
  /** Build a typed endpoint from a leaf. */
243
- build: <L extends AnyLeaf>(leaf: L, opts?: BuildOptionsFor<L>,
245
+ build: <L extends AnyLeafLowProfile>(leaf: L, opts?: BuildOptionsFor<L>,
244
246
  /** Optional metadata (third arg) to assign a debug name for filtering via `debug.only`. */
245
247
  meta?: BuildMeta<Names>) => BuiltForLeaf<L>;
246
248
  /** Underlying React Query client (exposed for advanced scenarios). */
247
249
  queryClient: QueryClient;
250
+ /**
251
+ * Low-level fetch helper that does not depend on a leaf definition.
252
+ * Handles path param interpolation and enforces flat string query objects.
253
+ */
254
+ fetch: RouteClientFetch;
248
255
  };
249
256
  /**
250
257
  * Helper signature returned by `buildRouter`, enabling lookups by name instead of leaves.
251
258
  * Accepts the same build options/meta the underlying client does, narrowed per leaf shape.
252
259
  */
253
- export type RouterBuilder<Routes extends Record<PropertyKey, AnyLeaf>, Names extends string = string> = <K extends keyof Routes>(key: K, opts?: BuildOptionsFor<Routes[K]>, meta?: BuildMeta<Names>) => BuiltForLeaf<Routes[K]>;
260
+ export type RouterBuilder<Routes extends Record<PropertyKey, AnyLeafLowProfile>, Names extends string = string> = <K extends keyof Routes>(key: K, opts?: BuildOptionsFor<Routes[K]>, meta?: BuildMeta<Names>) => BuiltForLeaf<Routes[K]>;
261
+ /**
262
+ * Arguments for the low-level RouteClient.fetch helper.
263
+ * This is intentionally NOT tied to AnyLeafLowProfile.
264
+ */
265
+ export type RouteClientFetchArgs = {
266
+ /**
267
+ * Route template or concrete path, e.g. "/api/users/:id".
268
+ * Params from `params` will be interpolated into any `:name` segments.
269
+ */
270
+ path: string;
271
+ /**
272
+ * HTTP method. Can be provided as lowercase (HttpMethod) or uppercase;
273
+ * the client normalizes it to uppercase internally.
274
+ */
275
+ method: HttpMethod | Uppercase<HttpMethod>;
276
+ /**
277
+ * Flat query string object. Only string values are allowed.
278
+ * Nested objects/arrays will cause a runtime error in the client.
279
+ */
280
+ query?: Record<string, string>;
281
+ /**
282
+ * Path parameters used to fill `:name` segments in the `path`.
283
+ * Extra keys that do not match a path segment, or non-primitive values,
284
+ * will cause a runtime error in the client.
285
+ */
286
+ params?: Record<string, string | number | boolean | null | undefined>;
287
+ /**
288
+ * Optional request body (already normalized by the caller).
289
+ */
290
+ body?: unknown;
291
+ };
292
+ /**
293
+ * Signature of the low-level RouteClient.fetch helper.
294
+ * Callers may specify a response type parameter if desired.
295
+ */
296
+ export type RouteClientFetch = (args: RouteClientFetchArgs) => Promise<any>;
254
297
  export {};
@@ -1,6 +1,6 @@
1
- import type { EventMap, SocketConnectionConfigOutput, Payload, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
- import type { MaybeSocket, SysEventMap } from './socket.client.sys';
1
+ import type { EventMap, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
3
2
  import { SocketClientDebugEvent } from './socket.client.debug';
3
+ import type { MaybeSocket, SysEventMap } from './socket.client.sys';
4
4
  export type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {
5
5
  eventName: K;
6
6
  sentAt: string | Date;
@@ -1,12 +1,12 @@
1
- import type { AnyLeaf, EventMap, InferOutput, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
1
+ import type { AnyLeafLowProfile, EventMap, InferOutput, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
2
  import type { BuiltInfinite, BuiltQuery, DataShape, InfiniteUseEndpointResultFor, QueryUseEndpointResultFor, UseEndpointArgs } from '../../routesV3.client.types';
3
3
  import type { ClientCtx, ServerEnvelope, SocketClient } from '../socket.client.index';
4
4
  type RoomsInput = string | string[] | undefined | null;
5
- type SocketedBuilt<L extends AnyLeaf> = L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L>;
6
- type SocketedRouteResult<L extends AnyLeaf> = (L['cfg']['feed'] extends true ? InfiniteUseEndpointResultFor<L> : QueryUseEndpointResultFor<L>) & {
5
+ type SocketedBuilt<L extends AnyLeafLowProfile> = L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L>;
6
+ type SocketedRouteResult<L extends AnyLeafLowProfile> = (L['cfg']['feed'] extends true ? InfiniteUseEndpointResultFor<L> : QueryUseEndpointResultFor<L>) & {
7
7
  rooms: string[];
8
8
  };
9
- export type SocketedRouteOptions<L extends AnyLeaf, Events extends EventMap, C extends SocketConnectionConfigOutput> = {
9
+ export type SocketedRouteOptions<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput> = {
10
10
  built: SocketedBuilt<L>;
11
11
  toRooms: (data: InferOutput<L>) => {
12
12
  rooms: RoomsInput;
@@ -26,5 +26,5 @@ export type SocketedRouteOptions<L extends AnyLeaf, Events extends EventMap, C e
26
26
  * - joins/leaves rooms derived from the endpoint data
27
27
  * - subscribes to a socket event and applies messages to the cache
28
28
  */
29
- export declare function buildSocketedRoute<L extends AnyLeaf, Events extends EventMap, C extends SocketConnectionConfigOutput>(options: SocketedRouteOptions<L, Events, C>): (...useArgs: UseEndpointArgs<L>) => SocketedRouteResult<L>;
29
+ export declare function buildSocketedRoute<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput>(options: SocketedRouteOptions<L, Events, C>): (...useArgs: UseEndpointArgs<L>) => SocketedRouteResult<L>;
30
30
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-client",
3
- "version": "2.2.14",
3
+ "version": "2.2.16",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -19,8 +19,8 @@
19
19
  "dist"
20
20
  ],
21
21
  "dependencies": {
22
- "@emeryld/rrroutes-contract": "^2.1.9",
23
- "zod": "^4.1.12"
22
+ "@emeryld/rrroutes-contract": "^2.3.9",
23
+ "zod": "^4.1.13"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@tanstack/react-query": "^5.87.4",