@spoosh/react 0.3.0 → 0.4.1

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 CHANGED
@@ -33,7 +33,7 @@ Fetch data with automatic caching and refetching.
33
33
  ```typescript
34
34
  function UserList() {
35
35
  const { data, loading, error, refetch } = useRead(
36
- (api) => api.users.$get()
36
+ (api) => api("users").GET()
37
37
  );
38
38
 
39
39
  if (loading) return <div>Loading...</div>;
@@ -48,12 +48,18 @@ function UserList() {
48
48
 
49
49
  // With options
50
50
  const { data } = useRead(
51
- (api) => api.users.$get({ query: { page: 1 } }),
51
+ (api) => api("users").GET({ query: { page: 1 } }),
52
52
  {
53
53
  staleTime: 10000,
54
54
  enabled: isReady,
55
55
  }
56
56
  );
57
+
58
+ // With path parameters
59
+ const { data: user } = useRead(
60
+ (api) => api("users/:id").GET({ params: { id: userId } }),
61
+ { enabled: !!userId }
62
+ );
57
63
  ```
58
64
 
59
65
  ### useWrite
@@ -63,7 +69,7 @@ Trigger mutations with loading and error states.
63
69
  ```typescript
64
70
  function CreateUser() {
65
71
  const { trigger, loading, error } = useWrite(
66
- (api) => api.users.$post
72
+ (api) => api("users").POST
67
73
  );
68
74
 
69
75
  const handleSubmit = async (data: CreateUserBody) => {
@@ -82,6 +88,14 @@ function CreateUser() {
82
88
  </form>
83
89
  );
84
90
  }
91
+
92
+ // With path parameters
93
+ const updateUser = useWrite((api) => api("users/:id").PUT);
94
+
95
+ await updateUser.trigger({
96
+ params: { id: userId },
97
+ body: { name: "Updated Name" },
98
+ });
85
99
  ```
86
100
 
87
101
  ### useInfiniteRead
@@ -101,7 +115,7 @@ function PostList() {
101
115
  fetchingNext,
102
116
  fetchingPrev,
103
117
  } = useInfiniteRead(
104
- (api) => api.posts.$get({ query: { page: 1 } }),
118
+ (api) => api("posts").GET({ query: { page: 1 } }),
105
119
  {
106
120
  // Required: Check if next page exists
107
121
  canFetchNext: ({ response }) => response?.meta.hasMore ?? false,
package/dist/index.d.mts CHANGED
@@ -1,9 +1,6 @@
1
1
  import * as _spoosh_core from '@spoosh/core';
2
- import { QueryOnlyClient, MethodOptionsMap, CoreRequestOptionsBase, TagOptions, SpooshResponse, MutationOnlyClient, SpooshPlugin, PluginTypeConfig, SpooshOptions, MergePluginResults, StateManager, EventEmitter, PluginExecutor, PluginArray, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
2
+ import { ReadClient, TagOptions, SpooshResponse, WriteClient, SpooshPlugin, PluginTypeConfig, SpooshOptions, MergePluginResults, StateManager, EventEmitter, PluginExecutor, PluginArray, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
3
3
 
4
- type QueryRequestOptions = CoreRequestOptionsBase;
5
- type MutationRequestOptions = CoreRequestOptionsBase;
6
- type ReactOptionsMap = MethodOptionsMap<QueryRequestOptions, MutationRequestOptions>;
7
4
  type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
8
5
  baseUrl: string;
9
6
  defaultOptions?: SpooshOptions;
@@ -74,24 +71,19 @@ type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined ext
74
71
  } : {
75
72
  body: TBody;
76
73
  };
77
- type OptionalFormDataField<TFormData> = [TFormData] extends [never] ? object : undefined extends TFormData ? {
78
- formData?: Exclude<TFormData, undefined>;
79
- } : {
80
- formData: TFormData;
81
- };
82
74
  type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
83
75
  never
84
76
  ] ? object : {
85
77
  params: Record<TParamNames, string | number>;
86
78
  };
87
- type InputFields<TQuery, TBody, TFormData, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalFormDataField<TFormData> & OptionalParamsField<TParamNames>;
88
- type WriteResponseInputFields<TQuery, TBody, TFormData, TParamNames extends string> = [TQuery, TBody, TFormData, TParamNames] extends [never, never, never, never] ? object : {
89
- input: InputFields<TQuery, TBody, TFormData, TParamNames> | undefined;
79
+ type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
80
+ type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
81
+ input: InputFields<TQuery, TBody, TParamNames> | undefined;
90
82
  };
91
83
  type UseReadResult<TData, TError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError> & MergePluginResults<TPlugins>["read"];
92
84
  type UseWriteResult<TData, TError, TOptions, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions> & MergePluginResults<TPlugins>["write"];
93
- type ReadApiClient<TSchema, TDefaultError> = QueryOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
94
- type WriteApiClient<TSchema, TDefaultError> = MutationOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
85
+ type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
86
+ type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
95
87
  type SuccessResponse<T> = Extract<T, {
96
88
  data: unknown;
97
89
  error?: undefined;
@@ -113,12 +105,6 @@ type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
113
105
  type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
114
106
  body: infer B;
115
107
  } ? B : never;
116
- type ExtractMethodFormData<T> = ExtractMethodOptions<T> extends {
117
- formData: infer F;
118
- } ? F : never;
119
- type ExtractMethodUrlEncoded<T> = ExtractMethodOptions<T> extends {
120
- urlEncoded: infer U;
121
- } ? U : never;
122
108
  type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
123
109
  type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
124
110
  type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
@@ -131,11 +117,6 @@ type ExtractResponseBody<T> = SuccessReturnType<T> extends {
131
117
  body: infer B;
132
118
  };
133
119
  } ? B : never;
134
- type ExtractResponseFormData<T> = SuccessReturnType<T> extends {
135
- input: {
136
- formData: infer F;
137
- };
138
- } ? F : never;
139
120
  type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
140
121
  input: {
141
122
  params: Record<infer K, unknown>;
@@ -151,17 +132,16 @@ type BodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBo
151
132
  } : {
152
133
  body: TBody;
153
134
  };
154
- type FormDataField<TFormData> = [TFormData] extends [never] ? object : undefined extends TFormData ? {
155
- formData?: Exclude<TFormData, undefined>;
156
- } : {
157
- formData: TFormData;
158
- };
159
135
  type ParamsField<TParamNames extends string> = [TParamNames] extends [never] ? object : {
160
136
  params: Record<TParamNames, string | number>;
161
137
  };
162
- type ReadInputFields<TQuery, TBody, TFormData, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & FormDataField<TFormData> & ParamsField<TParamNames>;
163
- type ResponseInputFields<TQuery, TBody, TFormData, TParamNames extends string> = [TQuery, TBody, TFormData, TParamNames] extends [never, never, never, never] ? object : {
164
- input: ReadInputFields<TQuery, TBody, TFormData, TParamNames>;
138
+ type ReadInputFields<TQuery, TBody, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & ParamsField<TParamNames>;
139
+ type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
140
+ TQuery,
141
+ TBody,
142
+ TParamNames
143
+ ] extends [never, never, never] ? object : {
144
+ input: ReadInputFields<TQuery, TBody, TParamNames>;
165
145
  };
166
146
  type AnyInfiniteRequestOptions = {
167
147
  query?: Record<string, unknown>;
@@ -250,26 +230,26 @@ type BaseInfiniteReadResult<TData, TError, TItem, TPluginResult = Record<string,
250
230
  error: TError | undefined;
251
231
  };
252
232
  type UseInfiniteReadResult<TData, TError, TItem, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseInfiniteReadResult<TData, TError, TItem> & MergePluginResults<TPlugins>["read"];
253
- type InfiniteReadApiClient<TSchema, TDefaultError> = QueryOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
233
+ type InfiniteReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
254
234
 
255
235
  type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
256
236
  type ExtractParamsRecord<T> = ExtractResponseParamNames<T> extends never ? never : Record<ExtractResponseParamNames<T>, string | number>;
257
- type ReadResolverContext<TSchema, TReadFn, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractParamsRecord<TReadFn>, ExtractResponseFormData<TReadFn>>;
237
+ type ReadResolverContext<TSchema, TReadFn, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractParamsRecord<TReadFn>>;
258
238
  type ResolvedReadOptions<TSchema, TPlugins extends PluginArray, TReadFn, TDefaultError> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["read"], ReadResolverContext<TSchema, TReadFn, TDefaultError>>;
259
- type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>;
239
+ type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>;
260
240
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
261
241
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
262
242
  data?: unknown;
263
243
  error?: unknown;
264
- }>>(readFn: TReadFn, readOptions?: BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>) => BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseFormData<TReadFn>, ExtractResponseParamNames<TReadFn>>;
265
- type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>, TWriteOpts extends (TMethod extends (options: infer O) => unknown ? O : object) & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError> = (TMethod extends (options: infer O) => unknown ? O : object) & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, TWriteOpts, ResolveResultTypes<MergePluginResults<TPlugins>["write"], TWriteOpts>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseFormData<TMethod>, ExtractResponseParamNames<TMethod>>;
244
+ }>>(readFn: TReadFn, readOptions?: BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>) => BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
245
+ type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TMethod extends (...args: never) => Promise<SpooshResponse<unknown, unknown>>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, Parameters<TMethod>[0] & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["write"], Parameters<TMethod>[0] & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>>> & WriteResponseInputFields<ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod>>;
266
246
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
267
247
  query: infer Q;
268
248
  } ? Q : never, TRequest extends {
269
249
  body: infer B;
270
250
  } ? B : never, TRequest extends {
271
251
  params: infer P;
272
- } ? P : never, never>;
252
+ } ? P : never>;
273
253
  type ResolvedInfiniteReadOptions<TSchema, TPlugins extends PluginArray, TData, TError, TRequest> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["infiniteRead"], InfiniteReadResolverContext<TSchema, TData, TError, TRequest>>;
274
254
  type UseInfiniteReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TData, TItem, TError = TDefaultError, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions>(readFn: (api: InfiniteReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<TData, TError>>, readOptions: BaseInfiniteReadOptions<TData, TItem, TRequest> & ResolvedInfiniteReadOptions<TSchema, TPlugins, TData, TError, TRequest>) => BaseInfiniteReadResult<TData, TError, TItem, MergePluginResults<TPlugins>["read"]>;
275
255
  /**
@@ -283,16 +263,16 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
283
263
  /**
284
264
  * React hook for fetching data from an API endpoint with automatic caching and revalidation.
285
265
  *
286
- * @param readFn - Function that selects the API endpoint to call (e.g., `(api) => api.posts.$get()`)
266
+ * @param readFn - Function that selects the API endpoint to call (e.g., `(api) => api("posts").GET()`)
287
267
  * @param readOptions - Optional configuration including `enabled`, `tags`, and plugin-specific options
288
268
  * @returns Object containing `data`, `error`, `loading`, `fetching`, `refetch`, and `abort`
289
269
  *
290
270
  * @example
291
271
  * ```tsx
292
- * const { data, loading, error } = useRead((api) => api.posts.$get());
272
+ * const { data, loading, error } = useRead((api) => api("posts").GET());
293
273
  *
294
274
  * const { data: post } = useRead(
295
- * (api) => api.posts(postId).$get(),
275
+ * (api) => api("posts/:id").GET({ params: { id: postId } }),
296
276
  * { enabled: !!postId }
297
277
  * );
298
278
  * ```
@@ -301,12 +281,12 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
301
281
  /**
302
282
  * React hook for mutations (POST, PUT, PATCH, DELETE) with manual triggering.
303
283
  *
304
- * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api.posts.$post`)
284
+ * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST`)
305
285
  * @returns Object containing `trigger`, `data`, `error`, `loading`, `reset`, and `abort`
306
286
  *
307
287
  * @example
308
288
  * ```tsx
309
- * const { trigger, loading, data } = useWrite((api) => api.posts.$post);
289
+ * const { trigger, loading, data } = useWrite((api) => api("posts").POST);
310
290
  *
311
291
  * const handleSubmit = async (formData) => {
312
292
  * const { data, error } = await trigger({ body: formData });
@@ -325,7 +305,7 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
325
305
  * @example
326
306
  * ```tsx
327
307
  * const { data, fetchNext, canFetchNext, loading } = useInfiniteRead(
328
- * (api) => api.posts.$get(),
308
+ * (api) => api("posts").GET(),
329
309
  * {
330
310
  * canFetchNext: ({ response }) => !!response?.nextCursor,
331
311
  * nextPageRequest: ({ response }) => ({ query: { cursor: response?.nextCursor } }),
@@ -371,7 +351,7 @@ type SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins> = {
371
351
  * const { useRead, useWrite, useInfiniteRead } = createReactSpoosh(spooshInstance);
372
352
  *
373
353
  * function MyComponent() {
374
- * const { data, loading } = useRead((api) => api.posts.$get());
354
+ * const { data, loading } = useRead((api) => api("posts").GET());
375
355
  * return <div>{loading ? 'Loading...' : data?.title}</div>;
376
356
  * }
377
357
  * ```
@@ -399,13 +379,13 @@ declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly
399
379
  readResult: infer R;
400
380
  } ? R : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
401
381
  readResult: infer R;
402
- } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseFormData<TReadFn>, ExtractResponseParamNames<TReadFn>>;
382
+ } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
403
383
 
404
384
  declare function createUseWrite<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodOptions<TMethod> & _spoosh_core.ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
405
385
  writeOptions: infer W;
406
386
  } ? W : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
407
387
  writeOptions: infer W;
408
- } ? W : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>>, ResolveResultTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
388
+ } ? W : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>>, ResolveResultTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
409
389
  writeResult: infer W_1;
410
390
  } ? W_1 : object : object : never : never) extends infer T_4 ? T_4 extends (TPlugins[number] extends infer T_5 ? T_5 extends TPlugins[number] ? T_5 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
411
391
  writeResult: infer W_1;
@@ -413,7 +393,7 @@ declare function createUseWrite<TSchema, TDefaultError, TPlugins extends readonl
413
393
  writeOptions: infer W;
414
394
  } ? W : object : object : never : never) extends infer T_7 ? T_7 extends (TPlugins[number] extends infer T_8 ? T_8 extends TPlugins[number] ? T_8 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
415
395
  writeOptions: infer W;
416
- } ? W : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>>>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseFormData<TMethod>, ExtractResponseParamNames<TMethod>>;
396
+ } ? W : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>>>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
417
397
 
418
398
  declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TData, TItem, TError = TDefaultError, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions>(readFn: (api: InfiniteReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<TData, TError>>, readOptions: BaseInfiniteReadOptions<TData, TItem, TRequest> & (((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
419
399
  infiniteReadOptions: infer I_1;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import * as _spoosh_core from '@spoosh/core';
2
- import { QueryOnlyClient, MethodOptionsMap, CoreRequestOptionsBase, TagOptions, SpooshResponse, MutationOnlyClient, SpooshPlugin, PluginTypeConfig, SpooshOptions, MergePluginResults, StateManager, EventEmitter, PluginExecutor, PluginArray, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
2
+ import { ReadClient, TagOptions, SpooshResponse, WriteClient, SpooshPlugin, PluginTypeConfig, SpooshOptions, MergePluginResults, StateManager, EventEmitter, PluginExecutor, PluginArray, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
3
3
 
4
- type QueryRequestOptions = CoreRequestOptionsBase;
5
- type MutationRequestOptions = CoreRequestOptionsBase;
6
- type ReactOptionsMap = MethodOptionsMap<QueryRequestOptions, MutationRequestOptions>;
7
4
  type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
8
5
  baseUrl: string;
9
6
  defaultOptions?: SpooshOptions;
@@ -74,24 +71,19 @@ type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined ext
74
71
  } : {
75
72
  body: TBody;
76
73
  };
77
- type OptionalFormDataField<TFormData> = [TFormData] extends [never] ? object : undefined extends TFormData ? {
78
- formData?: Exclude<TFormData, undefined>;
79
- } : {
80
- formData: TFormData;
81
- };
82
74
  type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
83
75
  never
84
76
  ] ? object : {
85
77
  params: Record<TParamNames, string | number>;
86
78
  };
87
- type InputFields<TQuery, TBody, TFormData, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalFormDataField<TFormData> & OptionalParamsField<TParamNames>;
88
- type WriteResponseInputFields<TQuery, TBody, TFormData, TParamNames extends string> = [TQuery, TBody, TFormData, TParamNames] extends [never, never, never, never] ? object : {
89
- input: InputFields<TQuery, TBody, TFormData, TParamNames> | undefined;
79
+ type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
80
+ type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
81
+ input: InputFields<TQuery, TBody, TParamNames> | undefined;
90
82
  };
91
83
  type UseReadResult<TData, TError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError> & MergePluginResults<TPlugins>["read"];
92
84
  type UseWriteResult<TData, TError, TOptions, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions> & MergePluginResults<TPlugins>["write"];
93
- type ReadApiClient<TSchema, TDefaultError> = QueryOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
94
- type WriteApiClient<TSchema, TDefaultError> = MutationOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
85
+ type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
86
+ type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
95
87
  type SuccessResponse<T> = Extract<T, {
96
88
  data: unknown;
97
89
  error?: undefined;
@@ -113,12 +105,6 @@ type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
113
105
  type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
114
106
  body: infer B;
115
107
  } ? B : never;
116
- type ExtractMethodFormData<T> = ExtractMethodOptions<T> extends {
117
- formData: infer F;
118
- } ? F : never;
119
- type ExtractMethodUrlEncoded<T> = ExtractMethodOptions<T> extends {
120
- urlEncoded: infer U;
121
- } ? U : never;
122
108
  type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
123
109
  type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
124
110
  type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
@@ -131,11 +117,6 @@ type ExtractResponseBody<T> = SuccessReturnType<T> extends {
131
117
  body: infer B;
132
118
  };
133
119
  } ? B : never;
134
- type ExtractResponseFormData<T> = SuccessReturnType<T> extends {
135
- input: {
136
- formData: infer F;
137
- };
138
- } ? F : never;
139
120
  type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
140
121
  input: {
141
122
  params: Record<infer K, unknown>;
@@ -151,17 +132,16 @@ type BodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBo
151
132
  } : {
152
133
  body: TBody;
153
134
  };
154
- type FormDataField<TFormData> = [TFormData] extends [never] ? object : undefined extends TFormData ? {
155
- formData?: Exclude<TFormData, undefined>;
156
- } : {
157
- formData: TFormData;
158
- };
159
135
  type ParamsField<TParamNames extends string> = [TParamNames] extends [never] ? object : {
160
136
  params: Record<TParamNames, string | number>;
161
137
  };
162
- type ReadInputFields<TQuery, TBody, TFormData, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & FormDataField<TFormData> & ParamsField<TParamNames>;
163
- type ResponseInputFields<TQuery, TBody, TFormData, TParamNames extends string> = [TQuery, TBody, TFormData, TParamNames] extends [never, never, never, never] ? object : {
164
- input: ReadInputFields<TQuery, TBody, TFormData, TParamNames>;
138
+ type ReadInputFields<TQuery, TBody, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & ParamsField<TParamNames>;
139
+ type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
140
+ TQuery,
141
+ TBody,
142
+ TParamNames
143
+ ] extends [never, never, never] ? object : {
144
+ input: ReadInputFields<TQuery, TBody, TParamNames>;
165
145
  };
166
146
  type AnyInfiniteRequestOptions = {
167
147
  query?: Record<string, unknown>;
@@ -250,26 +230,26 @@ type BaseInfiniteReadResult<TData, TError, TItem, TPluginResult = Record<string,
250
230
  error: TError | undefined;
251
231
  };
252
232
  type UseInfiniteReadResult<TData, TError, TItem, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseInfiniteReadResult<TData, TError, TItem> & MergePluginResults<TPlugins>["read"];
253
- type InfiniteReadApiClient<TSchema, TDefaultError> = QueryOnlyClient<TSchema, TDefaultError, ReactOptionsMap>;
233
+ type InfiniteReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
254
234
 
255
235
  type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
256
236
  type ExtractParamsRecord<T> = ExtractResponseParamNames<T> extends never ? never : Record<ExtractResponseParamNames<T>, string | number>;
257
- type ReadResolverContext<TSchema, TReadFn, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractParamsRecord<TReadFn>, ExtractResponseFormData<TReadFn>>;
237
+ type ReadResolverContext<TSchema, TReadFn, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractParamsRecord<TReadFn>>;
258
238
  type ResolvedReadOptions<TSchema, TPlugins extends PluginArray, TReadFn, TDefaultError> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["read"], ReadResolverContext<TSchema, TReadFn, TDefaultError>>;
259
- type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>;
239
+ type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>;
260
240
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
261
241
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
262
242
  data?: unknown;
263
243
  error?: unknown;
264
- }>>(readFn: TReadFn, readOptions?: BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>) => BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseFormData<TReadFn>, ExtractResponseParamNames<TReadFn>>;
265
- type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>, TWriteOpts extends (TMethod extends (options: infer O) => unknown ? O : object) & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError> = (TMethod extends (options: infer O) => unknown ? O : object) & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, TWriteOpts, ResolveResultTypes<MergePluginResults<TPlugins>["write"], TWriteOpts>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseFormData<TMethod>, ExtractResponseParamNames<TMethod>>;
244
+ }>>(readFn: TReadFn, readOptions?: BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>) => BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], BaseReadOptions & ResolvedReadOptions<TSchema, TPlugins, TReadFn, TDefaultError>>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
245
+ type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TMethod extends (...args: never) => Promise<SpooshResponse<unknown, unknown>>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, Parameters<TMethod>[0] & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["write"], Parameters<TMethod>[0] & ResolvedWriteOptions<TSchema, TPlugins, TMethod, TDefaultError>>> & WriteResponseInputFields<ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod>>;
266
246
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
267
247
  query: infer Q;
268
248
  } ? Q : never, TRequest extends {
269
249
  body: infer B;
270
250
  } ? B : never, TRequest extends {
271
251
  params: infer P;
272
- } ? P : never, never>;
252
+ } ? P : never>;
273
253
  type ResolvedInfiniteReadOptions<TSchema, TPlugins extends PluginArray, TData, TError, TRequest> = _spoosh_core.ResolveTypes<MergePluginOptions<TPlugins>["infiniteRead"], InfiniteReadResolverContext<TSchema, TData, TError, TRequest>>;
274
254
  type UseInfiniteReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = <TData, TItem, TError = TDefaultError, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions>(readFn: (api: InfiniteReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<TData, TError>>, readOptions: BaseInfiniteReadOptions<TData, TItem, TRequest> & ResolvedInfiniteReadOptions<TSchema, TPlugins, TData, TError, TRequest>) => BaseInfiniteReadResult<TData, TError, TItem, MergePluginResults<TPlugins>["read"]>;
275
255
  /**
@@ -283,16 +263,16 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
283
263
  /**
284
264
  * React hook for fetching data from an API endpoint with automatic caching and revalidation.
285
265
  *
286
- * @param readFn - Function that selects the API endpoint to call (e.g., `(api) => api.posts.$get()`)
266
+ * @param readFn - Function that selects the API endpoint to call (e.g., `(api) => api("posts").GET()`)
287
267
  * @param readOptions - Optional configuration including `enabled`, `tags`, and plugin-specific options
288
268
  * @returns Object containing `data`, `error`, `loading`, `fetching`, `refetch`, and `abort`
289
269
  *
290
270
  * @example
291
271
  * ```tsx
292
- * const { data, loading, error } = useRead((api) => api.posts.$get());
272
+ * const { data, loading, error } = useRead((api) => api("posts").GET());
293
273
  *
294
274
  * const { data: post } = useRead(
295
- * (api) => api.posts(postId).$get(),
275
+ * (api) => api("posts/:id").GET({ params: { id: postId } }),
296
276
  * { enabled: !!postId }
297
277
  * );
298
278
  * ```
@@ -301,12 +281,12 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
301
281
  /**
302
282
  * React hook for mutations (POST, PUT, PATCH, DELETE) with manual triggering.
303
283
  *
304
- * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api.posts.$post`)
284
+ * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST`)
305
285
  * @returns Object containing `trigger`, `data`, `error`, `loading`, `reset`, and `abort`
306
286
  *
307
287
  * @example
308
288
  * ```tsx
309
- * const { trigger, loading, data } = useWrite((api) => api.posts.$post);
289
+ * const { trigger, loading, data } = useWrite((api) => api("posts").POST);
310
290
  *
311
291
  * const handleSubmit = async (formData) => {
312
292
  * const { data, error } = await trigger({ body: formData });
@@ -325,7 +305,7 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
325
305
  * @example
326
306
  * ```tsx
327
307
  * const { data, fetchNext, canFetchNext, loading } = useInfiniteRead(
328
- * (api) => api.posts.$get(),
308
+ * (api) => api("posts").GET(),
329
309
  * {
330
310
  * canFetchNext: ({ response }) => !!response?.nextCursor,
331
311
  * nextPageRequest: ({ response }) => ({ query: { cursor: response?.nextCursor } }),
@@ -371,7 +351,7 @@ type SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins> = {
371
351
  * const { useRead, useWrite, useInfiniteRead } = createReactSpoosh(spooshInstance);
372
352
  *
373
353
  * function MyComponent() {
374
- * const { data, loading } = useRead((api) => api.posts.$get());
354
+ * const { data, loading } = useRead((api) => api("posts").GET());
375
355
  * return <div>{loading ? 'Loading...' : data?.title}</div>;
376
356
  * }
377
357
  * ```
@@ -399,13 +379,13 @@ declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly
399
379
  readResult: infer R;
400
380
  } ? R : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
401
381
  readResult: infer R;
402
- } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseFormData<TReadFn>, ExtractResponseParamNames<TReadFn>>;
382
+ } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
403
383
 
404
384
  declare function createUseWrite<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(writeFn: (api: WriteApiClient<TSchema, TDefaultError>) => TMethod) => BaseWriteResult<ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodOptions<TMethod> & _spoosh_core.ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
405
385
  writeOptions: infer W;
406
386
  } ? W : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
407
387
  writeOptions: infer W;
408
- } ? W : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>>, ResolveResultTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
388
+ } ? W : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>>, ResolveResultTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
409
389
  writeResult: infer W_1;
410
390
  } ? W_1 : object : object : never : never) extends infer T_4 ? T_4 extends (TPlugins[number] extends infer T_5 ? T_5 extends TPlugins[number] ? T_5 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
411
391
  writeResult: infer W_1;
@@ -413,7 +393,7 @@ declare function createUseWrite<TSchema, TDefaultError, TPlugins extends readonl
413
393
  writeOptions: infer W;
414
394
  } ? W : object : object : never : never) extends infer T_7 ? T_7 extends (TPlugins[number] extends infer T_8 ? T_8 extends TPlugins[number] ? T_8 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
415
395
  writeOptions: infer W;
416
- } ? W : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>, ExtractMethodFormData<TMethod>, ExtractMethodUrlEncoded<TMethod>>>>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseFormData<TMethod>, ExtractResponseParamNames<TMethod>>;
396
+ } ? W : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>>>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
417
397
 
418
398
  declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TData, TItem, TError = TDefaultError, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions>(readFn: (api: InfiniteReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<TData, TError>>, readOptions: BaseInfiniteReadOptions<TData, TItem, TRequest> & (((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
419
399
  infiniteReadOptions: infer I_1;
package/dist/index.js CHANGED
@@ -53,14 +53,15 @@ function createUseRead(options) {
53
53
  const capturedCall = selectorResultRef.current.call;
54
54
  if (!capturedCall) {
55
55
  throw new Error(
56
- "useRead requires calling an HTTP method ($get). Example: useRead((api) => api.posts.$get())"
56
+ 'useRead requires calling an HTTP method (GET). Example: useRead((api) => api("posts").GET())'
57
57
  );
58
58
  }
59
59
  const requestOptions = capturedCall.options;
60
- const resolvedPath = (0, import_core.resolvePath)(capturedCall.path, requestOptions?.params);
60
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
61
+ const resolvedPath = (0, import_core.resolvePath)(pathSegments, requestOptions?.params);
61
62
  const resolvedTags = (0, import_core.resolveTags)({ tags, additionalTags }, resolvedPath);
62
63
  const queryKey = stateManager.createQueryKey({
63
- path: capturedCall.path,
64
+ path: pathSegments,
64
65
  method: capturedCall.method,
65
66
  options: capturedCall.options
66
67
  });
@@ -75,7 +76,7 @@ function createUseRead(options) {
75
76
  if (!controllerRef.current || controllerRef.current.queryKey !== queryKey) {
76
77
  const controller2 = (0, import_core.createOperationController)({
77
78
  operationType: "read",
78
- path: capturedCall.path,
79
+ path: pathSegments,
79
80
  method: capturedCall.method,
80
81
  tags: resolvedTags,
81
82
  requestOptions: capturedCall.options,
@@ -84,11 +85,8 @@ function createUseRead(options) {
84
85
  pluginExecutor,
85
86
  hookId,
86
87
  fetchFn: async (fetchOpts) => {
87
- let current = api;
88
- for (const segment of resolvedPath) {
89
- current = current[segment];
90
- }
91
- const method = current[capturedCall.method];
88
+ const pathMethods = api(capturedCall.path);
89
+ const method = pathMethods[capturedCall.method];
92
90
  return method(fetchOpts);
93
91
  }
94
92
  });
@@ -186,9 +184,6 @@ function createUseRead(options) {
186
184
  if (opts?.body !== void 0) {
187
185
  inputInner.body = opts.body;
188
186
  }
189
- if (opts?.formData !== void 0) {
190
- inputInner.formData = opts.formData;
191
- }
192
187
  if (opts?.params !== void 0) {
193
188
  inputInner.params = opts.params;
194
189
  }
@@ -228,11 +223,12 @@ function createUseWrite(options) {
228
223
  const selectedEndpoint = selectorResultRef.current.selector;
229
224
  if (!selectedEndpoint) {
230
225
  throw new Error(
231
- "useWrite requires selecting an HTTP method ($post, $put, $patch, $delete). Example: useWrite((api) => api.posts.$post)"
226
+ 'useWrite requires selecting an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST)'
232
227
  );
233
228
  }
229
+ const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
234
230
  const queryKey = stateManager.createQueryKey({
235
- path: selectedEndpoint.path,
231
+ path: pathSegments,
236
232
  method: selectedEndpoint.method,
237
233
  options: void 0
238
234
  });
@@ -241,7 +237,7 @@ function createUseWrite(options) {
241
237
  controllerRef.current = {
242
238
  controller: (0, import_core2.createOperationController)({
243
239
  operationType: "write",
244
- path: selectedEndpoint.path,
240
+ path: pathSegments,
245
241
  method: selectedEndpoint.method,
246
242
  tags: [],
247
243
  stateManager,
@@ -249,13 +245,8 @@ function createUseWrite(options) {
249
245
  pluginExecutor,
250
246
  hookId,
251
247
  fetchFn: async (fetchOpts) => {
252
- const params = fetchOpts?.params;
253
- const resolvedPath = (0, import_core2.resolvePath)(selectedEndpoint.path, params);
254
- let current = api;
255
- for (const segment of resolvedPath) {
256
- current = current[segment];
257
- }
258
- const method = current[selectedEndpoint.method];
248
+ const pathMethods = api(selectedEndpoint.path);
249
+ const method = pathMethods[selectedEndpoint.method];
259
250
  return method(fetchOpts);
260
251
  }
261
252
  }),
@@ -282,7 +273,7 @@ function createUseWrite(options) {
282
273
  setLastTriggerOptions(triggerOptions);
283
274
  setRequestState((prev) => ({ ...prev, isPending: true }));
284
275
  const params = triggerOptions?.params;
285
- const resolvedPath = (0, import_core2.resolvePath)(selectedEndpoint.path, params);
276
+ const resolvedPath = (0, import_core2.resolvePath)(pathSegments, params);
286
277
  const tags = (0, import_core2.resolveTags)(triggerOptions, resolvedPath);
287
278
  controller.setPluginOptions({ ...triggerOptions, tags });
288
279
  try {
@@ -312,9 +303,6 @@ function createUseWrite(options) {
312
303
  if (opts?.body !== void 0) {
313
304
  inputInner.body = opts.body;
314
305
  }
315
- if (opts?.formData !== void 0) {
316
- inputInner.formData = opts.formData;
317
- }
318
306
  if (opts?.params !== void 0) {
319
307
  inputInner.params = opts.params;
320
308
  }
@@ -363,10 +351,11 @@ function createUseInfiniteRead(options) {
363
351
  const capturedCall = selectorResultRef.current.call;
364
352
  if (!capturedCall) {
365
353
  throw new Error(
366
- "useInfiniteRead requires calling an HTTP method ($get). Example: useInfiniteRead((api) => api.posts.$get())"
354
+ 'useInfiniteRead requires calling an HTTP method (GET). Example: useInfiniteRead((api) => api("posts").GET())'
367
355
  );
368
356
  }
369
357
  const requestOptions = capturedCall.options;
358
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
370
359
  const initialRequest = {
371
360
  query: requestOptions?.query,
372
361
  params: requestOptions?.params,
@@ -378,7 +367,7 @@ function createUseInfiniteRead(options) {
378
367
  params: void 0,
379
368
  body: void 0
380
369
  };
381
- const resolvedPath = (0, import_core3.resolvePath)(capturedCall.path, requestOptions?.params);
370
+ const resolvedPath = (0, import_core3.resolvePath)(pathSegments, requestOptions?.params);
382
371
  const resolvedTags = (0, import_core3.resolveTags)({ tags, additionalTags }, resolvedPath);
383
372
  const canFetchNextRef = (0, import_react3.useRef)(canFetchNext);
384
373
  const canFetchPrevRef = (0, import_react3.useRef)(canFetchPrev);
@@ -391,7 +380,7 @@ function createUseInfiniteRead(options) {
391
380
  prevPageRequestRef.current = prevPageRequest;
392
381
  mergerRef.current = merger;
393
382
  const queryKey = stateManager.createQueryKey({
394
- path: capturedCall.path,
383
+ path: pathSegments,
395
384
  method: capturedCall.method,
396
385
  options: baseOptionsForKey
397
386
  });
@@ -399,7 +388,7 @@ function createUseInfiniteRead(options) {
399
388
  if (!controllerRef.current || controllerRef.current.queryKey !== queryKey) {
400
389
  controllerRef.current = {
401
390
  controller: (0, import_core3.createInfiniteReadController)({
402
- path: capturedCall.path,
391
+ path: pathSegments,
403
392
  method: capturedCall.method,
404
393
  tags: resolvedTags,
405
394
  initialRequest,
@@ -414,12 +403,8 @@ function createUseInfiniteRead(options) {
414
403
  pluginExecutor,
415
404
  hookId,
416
405
  fetchFn: async (opts, signal) => {
417
- const fetchPath = (0, import_core3.resolvePath)(capturedCall.path, opts.params);
418
- let current = api;
419
- for (const segment of fetchPath) {
420
- current = current[segment];
421
- }
422
- const method = current[capturedCall.method];
406
+ const pathMethods = api(capturedCall.path);
407
+ const method = pathMethods[capturedCall.method];
423
408
  const fetchOptions = {
424
409
  ...capturedCall.options,
425
410
  query: opts.query,
package/dist/index.mjs CHANGED
@@ -37,14 +37,15 @@ function createUseRead(options) {
37
37
  const capturedCall = selectorResultRef.current.call;
38
38
  if (!capturedCall) {
39
39
  throw new Error(
40
- "useRead requires calling an HTTP method ($get). Example: useRead((api) => api.posts.$get())"
40
+ 'useRead requires calling an HTTP method (GET). Example: useRead((api) => api("posts").GET())'
41
41
  );
42
42
  }
43
43
  const requestOptions = capturedCall.options;
44
- const resolvedPath = resolvePath(capturedCall.path, requestOptions?.params);
44
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
45
+ const resolvedPath = resolvePath(pathSegments, requestOptions?.params);
45
46
  const resolvedTags = resolveTags({ tags, additionalTags }, resolvedPath);
46
47
  const queryKey = stateManager.createQueryKey({
47
- path: capturedCall.path,
48
+ path: pathSegments,
48
49
  method: capturedCall.method,
49
50
  options: capturedCall.options
50
51
  });
@@ -59,7 +60,7 @@ function createUseRead(options) {
59
60
  if (!controllerRef.current || controllerRef.current.queryKey !== queryKey) {
60
61
  const controller2 = createOperationController({
61
62
  operationType: "read",
62
- path: capturedCall.path,
63
+ path: pathSegments,
63
64
  method: capturedCall.method,
64
65
  tags: resolvedTags,
65
66
  requestOptions: capturedCall.options,
@@ -68,11 +69,8 @@ function createUseRead(options) {
68
69
  pluginExecutor,
69
70
  hookId,
70
71
  fetchFn: async (fetchOpts) => {
71
- let current = api;
72
- for (const segment of resolvedPath) {
73
- current = current[segment];
74
- }
75
- const method = current[capturedCall.method];
72
+ const pathMethods = api(capturedCall.path);
73
+ const method = pathMethods[capturedCall.method];
76
74
  return method(fetchOpts);
77
75
  }
78
76
  });
@@ -170,9 +168,6 @@ function createUseRead(options) {
170
168
  if (opts?.body !== void 0) {
171
169
  inputInner.body = opts.body;
172
170
  }
173
- if (opts?.formData !== void 0) {
174
- inputInner.formData = opts.formData;
175
- }
176
171
  if (opts?.params !== void 0) {
177
172
  inputInner.params = opts.params;
178
173
  }
@@ -223,11 +218,12 @@ function createUseWrite(options) {
223
218
  const selectedEndpoint = selectorResultRef.current.selector;
224
219
  if (!selectedEndpoint) {
225
220
  throw new Error(
226
- "useWrite requires selecting an HTTP method ($post, $put, $patch, $delete). Example: useWrite((api) => api.posts.$post)"
221
+ 'useWrite requires selecting an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST)'
227
222
  );
228
223
  }
224
+ const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
229
225
  const queryKey = stateManager.createQueryKey({
230
- path: selectedEndpoint.path,
226
+ path: pathSegments,
231
227
  method: selectedEndpoint.method,
232
228
  options: void 0
233
229
  });
@@ -236,7 +232,7 @@ function createUseWrite(options) {
236
232
  controllerRef.current = {
237
233
  controller: createOperationController2({
238
234
  operationType: "write",
239
- path: selectedEndpoint.path,
235
+ path: pathSegments,
240
236
  method: selectedEndpoint.method,
241
237
  tags: [],
242
238
  stateManager,
@@ -244,13 +240,8 @@ function createUseWrite(options) {
244
240
  pluginExecutor,
245
241
  hookId,
246
242
  fetchFn: async (fetchOpts) => {
247
- const params = fetchOpts?.params;
248
- const resolvedPath = resolvePath2(selectedEndpoint.path, params);
249
- let current = api;
250
- for (const segment of resolvedPath) {
251
- current = current[segment];
252
- }
253
- const method = current[selectedEndpoint.method];
243
+ const pathMethods = api(selectedEndpoint.path);
244
+ const method = pathMethods[selectedEndpoint.method];
254
245
  return method(fetchOpts);
255
246
  }
256
247
  }),
@@ -277,7 +268,7 @@ function createUseWrite(options) {
277
268
  setLastTriggerOptions(triggerOptions);
278
269
  setRequestState((prev) => ({ ...prev, isPending: true }));
279
270
  const params = triggerOptions?.params;
280
- const resolvedPath = resolvePath2(selectedEndpoint.path, params);
271
+ const resolvedPath = resolvePath2(pathSegments, params);
281
272
  const tags = resolveTags2(triggerOptions, resolvedPath);
282
273
  controller.setPluginOptions({ ...triggerOptions, tags });
283
274
  try {
@@ -307,9 +298,6 @@ function createUseWrite(options) {
307
298
  if (opts?.body !== void 0) {
308
299
  inputInner.body = opts.body;
309
300
  }
310
- if (opts?.formData !== void 0) {
311
- inputInner.formData = opts.formData;
312
- }
313
301
  if (opts?.params !== void 0) {
314
302
  inputInner.params = opts.params;
315
303
  }
@@ -369,10 +357,11 @@ function createUseInfiniteRead(options) {
369
357
  const capturedCall = selectorResultRef.current.call;
370
358
  if (!capturedCall) {
371
359
  throw new Error(
372
- "useInfiniteRead requires calling an HTTP method ($get). Example: useInfiniteRead((api) => api.posts.$get())"
360
+ 'useInfiniteRead requires calling an HTTP method (GET). Example: useInfiniteRead((api) => api("posts").GET())'
373
361
  );
374
362
  }
375
363
  const requestOptions = capturedCall.options;
364
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
376
365
  const initialRequest = {
377
366
  query: requestOptions?.query,
378
367
  params: requestOptions?.params,
@@ -384,7 +373,7 @@ function createUseInfiniteRead(options) {
384
373
  params: void 0,
385
374
  body: void 0
386
375
  };
387
- const resolvedPath = resolvePath3(capturedCall.path, requestOptions?.params);
376
+ const resolvedPath = resolvePath3(pathSegments, requestOptions?.params);
388
377
  const resolvedTags = resolveTags3({ tags, additionalTags }, resolvedPath);
389
378
  const canFetchNextRef = useRef3(canFetchNext);
390
379
  const canFetchPrevRef = useRef3(canFetchPrev);
@@ -397,7 +386,7 @@ function createUseInfiniteRead(options) {
397
386
  prevPageRequestRef.current = prevPageRequest;
398
387
  mergerRef.current = merger;
399
388
  const queryKey = stateManager.createQueryKey({
400
- path: capturedCall.path,
389
+ path: pathSegments,
401
390
  method: capturedCall.method,
402
391
  options: baseOptionsForKey
403
392
  });
@@ -405,7 +394,7 @@ function createUseInfiniteRead(options) {
405
394
  if (!controllerRef.current || controllerRef.current.queryKey !== queryKey) {
406
395
  controllerRef.current = {
407
396
  controller: createInfiniteReadController({
408
- path: capturedCall.path,
397
+ path: pathSegments,
409
398
  method: capturedCall.method,
410
399
  tags: resolvedTags,
411
400
  initialRequest,
@@ -420,12 +409,8 @@ function createUseInfiniteRead(options) {
420
409
  pluginExecutor,
421
410
  hookId,
422
411
  fetchFn: async (opts, signal) => {
423
- const fetchPath = resolvePath3(capturedCall.path, opts.params);
424
- let current = api;
425
- for (const segment of fetchPath) {
426
- current = current[segment];
427
- }
428
- const method = current[capturedCall.method];
412
+ const pathMethods = api(capturedCall.path);
413
+ const method = pathMethods[capturedCall.method];
429
414
  const fetchOptions = {
430
415
  ...capturedCall.options,
431
416
  query: opts.query,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/react",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "license": "MIT",
5
5
  "description": "React hooks for Spoosh API client",
6
6
  "keywords": [
@@ -34,11 +34,11 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "@spoosh/core": ">=0.4.0",
37
+ "@spoosh/core": ">=0.6.0",
38
38
  "react": "^18 || ^19"
39
39
  },
40
40
  "devDependencies": {
41
- "@spoosh/core": "0.5.0"
41
+ "@spoosh/core": "0.6.0"
42
42
  },
43
43
  "scripts": {
44
44
  "dev": "tsup --watch",