@spoosh/react 0.6.0 → 0.7.0

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
@@ -1,6 +1,6 @@
1
1
  # @spoosh/react
2
2
 
3
- React hooks for Spoosh - `useRead`, `useLazyRead`, `useWrite`, and `useInfiniteRead`.
3
+ React hooks for Spoosh - `useRead`, `useWrite`, and `useInfiniteRead`.
4
4
 
5
5
  **[Documentation](https://spoosh.dev/docs/integrations/react)** · **Requirements:** TypeScript >= 5.0, React >= 18.0
6
6
 
@@ -23,8 +23,7 @@ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
23
23
  cachePlugin({ staleTime: 5000 }),
24
24
  ]);
25
25
 
26
- export const { useRead, useLazyRead, useWrite, useInfiniteRead } =
27
- createReactSpoosh(spoosh);
26
+ export const { useRead, useWrite, useInfiniteRead } = createReactSpoosh(spoosh);
28
27
  ```
29
28
 
30
29
  ### useRead
@@ -63,27 +62,6 @@ const { data: user } = useRead(
63
62
  );
64
63
  ```
65
64
 
66
- ### useLazyRead
67
-
68
- Lazy data fetching for print/download/export scenarios. Does not auto-fetch on mount.
69
-
70
- ```typescript
71
- function PrintOrder() {
72
- const { trigger, loading } = useLazyRead((api) => api("orders/:id").GET);
73
-
74
- const handlePrint = async (orderId: string) => {
75
- const { data } = await trigger({ params: { id: orderId } });
76
- if (data) printReceipt(data);
77
- };
78
-
79
- return (
80
- <button onClick={() => handlePrint("123")} disabled={loading}>
81
- {loading ? "Loading..." : "Print"}
82
- </button>
83
- );
84
- }
85
- ```
86
-
87
65
  ### useWrite
88
66
 
89
67
  Trigger mutations with loading and error states.
package/dist/index.d.mts CHANGED
@@ -27,8 +27,11 @@ type BaseReadOptions = {
27
27
  * @template TData - The response data type
28
28
  * @template TError - The error type
29
29
  * @template TMeta - Plugin-provided metadata fields
30
+ * @template TTriggerOptions - Options that can be passed to trigger()
30
31
  */
31
- type BaseReadResult<TData, TError, TMeta = Record<string, unknown>> = {
32
+ type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
33
+ force?: boolean;
34
+ }> = {
32
35
  /** True during the initial load (no data yet) */
33
36
  loading: boolean;
34
37
  /** True during any fetch operation */
@@ -41,8 +44,12 @@ type BaseReadResult<TData, TError, TMeta = Record<string, unknown>> = {
41
44
  meta: TMeta;
42
45
  /** Abort the current fetch operation */
43
46
  abort: () => void;
44
- /** Manually trigger a fetch */
45
- trigger: () => Promise<SpooshResponse<TData, TError>>;
47
+ /**
48
+ * Manually trigger a fetch.
49
+ *
50
+ * @param options - Optional override options (query, body, params) to use for this specific request
51
+ */
52
+ trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
46
53
  };
47
54
  /**
48
55
  * Result returned by `useWrite` hook.
@@ -66,25 +73,6 @@ type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> =
66
73
  /** Abort the current mutation */
67
74
  abort: () => void;
68
75
  };
69
- /**
70
- * Result returned by `useLazyRead` hook.
71
- *
72
- * @template TData - The response data type
73
- * @template TError - The error type
74
- * @template TOptions - The trigger options type
75
- */
76
- type BaseLazyReadResult<TData, TError, TOptions> = {
77
- /** Execute the fetch with optional options */
78
- trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
79
- /** True while the fetch is in progress */
80
- loading: boolean;
81
- /** Response data from the API */
82
- data: TData | undefined;
83
- /** Error from the last failed request */
84
- error: TError | undefined;
85
- /** Abort the current fetch */
86
- abort: () => void;
87
- };
88
76
  type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
89
77
  query?: Exclude<TQuery, undefined>;
90
78
  } : {
@@ -123,7 +111,6 @@ type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResp
123
111
  error: infer E;
124
112
  } ? E : unknown : unknown;
125
113
  type ExtractMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] : never;
126
- type ExtractCoreMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "params" | "body">> : object : object;
127
114
  type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
128
115
  query: infer Q;
129
116
  } ? Q : never;
@@ -147,6 +134,33 @@ type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
147
134
  params: Record<infer K, unknown>;
148
135
  };
149
136
  } ? K extends string ? K : never : never;
137
+ type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
138
+ type ExtractInputFromResponse<T> = T extends {
139
+ input: infer I;
140
+ } ? I : never;
141
+ type ExtractTriggerQuery<I> = I extends {
142
+ query: infer Q;
143
+ } ? {
144
+ query?: Q;
145
+ } : unknown;
146
+ type ExtractTriggerBody<I> = I extends {
147
+ body: infer B;
148
+ } ? {
149
+ body?: B;
150
+ } : unknown;
151
+ type ExtractTriggerParams<I> = I extends {
152
+ params: infer P;
153
+ } ? {
154
+ params?: P;
155
+ } : unknown;
156
+ type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? {
157
+ force?: boolean;
158
+ } : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> & {
159
+ /** Force refetch even if data is cached */
160
+ force?: boolean;
161
+ } : {
162
+ force?: boolean;
163
+ };
150
164
  type QueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
151
165
  query?: Exclude<TQuery, undefined>;
152
166
  } : {
@@ -269,21 +283,12 @@ type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
269
283
  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>>;
270
284
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
271
285
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
272
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
273
- data?: unknown;
274
- error?: unknown;
275
- }>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<MergePluginOptions<TPlugins>["read"], ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
276
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
277
- data?: unknown;
278
- error?: unknown;
279
- }>>(readFn: TReadFn): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, MergePluginResults<TPlugins>["read"]> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
286
+ <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<MergePluginOptions<TPlugins>["read"], ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>, TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
287
+ <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>>(readFn: TReadFn): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, MergePluginResults<TPlugins>["read"], TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
280
288
  };
281
289
  type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
282
290
  <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>, MergePluginResults<TPlugins>["write"]> & WriteResponseInputFields<ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod>>;
283
291
  };
284
- type UseLazyReadFn<TDefaultError, TSchema> = {
285
- <TMethod extends (...args: never) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod): BaseLazyReadResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractCoreMethodOptions<TMethod>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
286
- };
287
292
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
288
293
  query: infer Q;
289
294
  } ? Q : never, TRequest extends {
@@ -336,23 +341,6 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
336
341
  * ```
337
342
  */
338
343
  useWrite: UseWriteFn<TDefaultError, TSchema, TPlugins>;
339
- /**
340
- * React hook for lazy GET requests with manual triggering (does not auto-fetch on mount).
341
- *
342
- * @param readFn - Function that selects the API endpoint (e.g., `(api) => api("posts").GET`)
343
- * @returns Object containing `trigger`, `data`, `error`, `loading`, and `abort`
344
- *
345
- * @example
346
- * ```tsx
347
- * const { trigger, loading, data } = useLazyRead((api) => api("posts/:id").GET);
348
- *
349
- * const handleClick = async (id) => {
350
- * const { data, error } = await trigger({ params: { id } });
351
- * if (data) console.log('Fetched:', data);
352
- * };
353
- * ```
354
- */
355
- useLazyRead: UseLazyReadFn<TDefaultError, TSchema>;
356
344
  /**
357
345
  * React hook for infinite/paginated data fetching with automatic pagination control.
358
346
  *
@@ -416,40 +404,33 @@ type SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins> = {
416
404
  */
417
405
  declare function createReactSpoosh<TSchema, TDefaultError, TPlugins extends PluginArray, TApi>(instance: SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins>): SpooshReactHooks<TDefaultError, TSchema, TPlugins>;
418
406
 
419
- declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): {
420
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
421
- data?: unknown;
422
- error?: unknown;
423
- }>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
424
- readOptions: infer R;
425
- } ? 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 {
426
- readOptions: infer R;
427
- } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
428
- data: infer D;
429
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
430
- error: infer E;
431
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
432
- error: infer E;
433
- }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
434
- data: infer D;
435
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
436
- error: infer E;
437
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
438
- error: infer E;
439
- }> ? E : unknown, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
440
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
441
- data?: unknown;
442
- error?: unknown;
443
- }>>(readFn: TReadFn): BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
444
- data: infer D;
445
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
446
- error: infer E;
447
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
448
- error: infer E;
449
- }> ? E : unknown, MergePluginResults<TPlugins>["read"]> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
450
- };
451
-
452
- declare function createUseLazyRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod) => BaseLazyReadResult<ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractCoreMethodOptions<TMethod>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
407
+ declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TReadOpts extends BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
408
+ readOptions: infer R;
409
+ } ? 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 {
410
+ readOptions: infer R;
411
+ } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
412
+ data: infer D;
413
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
414
+ error: infer E;
415
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
416
+ error: infer E;
417
+ }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>> = BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
418
+ readOptions: infer R;
419
+ } ? R : 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 extends PluginTypeConfig> ? Types extends {
420
+ readOptions: infer R;
421
+ } ? R : object : object : never : never) ? T_4 extends unknown ? (x: T_4) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
422
+ data: infer D;
423
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
424
+ error: infer E;
425
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
426
+ error: infer E;
427
+ }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>>(readFn: TReadFn, readOptions?: TReadOpts) => BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
428
+ data: infer D;
429
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
430
+ error: infer E;
431
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
432
+ error: infer E;
433
+ }> ? E : unknown, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>, TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
453
434
 
454
435
  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> & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
455
436
  writeOptions: infer W;
@@ -467,4 +448,4 @@ declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends
467
448
  readResult: infer R;
468
449
  } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never>;
469
450
 
470
- export { type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseLazyReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type PluginHooksConfig, type SpooshReactHooks, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, createReactSpoosh, createUseInfiniteRead, createUseLazyRead, createUseRead, createUseWrite };
451
+ export { type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type PluginHooksConfig, type SpooshReactHooks, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, createReactSpoosh, createUseInfiniteRead, createUseRead, createUseWrite };
package/dist/index.d.ts CHANGED
@@ -27,8 +27,11 @@ type BaseReadOptions = {
27
27
  * @template TData - The response data type
28
28
  * @template TError - The error type
29
29
  * @template TMeta - Plugin-provided metadata fields
30
+ * @template TTriggerOptions - Options that can be passed to trigger()
30
31
  */
31
- type BaseReadResult<TData, TError, TMeta = Record<string, unknown>> = {
32
+ type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
33
+ force?: boolean;
34
+ }> = {
32
35
  /** True during the initial load (no data yet) */
33
36
  loading: boolean;
34
37
  /** True during any fetch operation */
@@ -41,8 +44,12 @@ type BaseReadResult<TData, TError, TMeta = Record<string, unknown>> = {
41
44
  meta: TMeta;
42
45
  /** Abort the current fetch operation */
43
46
  abort: () => void;
44
- /** Manually trigger a fetch */
45
- trigger: () => Promise<SpooshResponse<TData, TError>>;
47
+ /**
48
+ * Manually trigger a fetch.
49
+ *
50
+ * @param options - Optional override options (query, body, params) to use for this specific request
51
+ */
52
+ trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
46
53
  };
47
54
  /**
48
55
  * Result returned by `useWrite` hook.
@@ -66,25 +73,6 @@ type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> =
66
73
  /** Abort the current mutation */
67
74
  abort: () => void;
68
75
  };
69
- /**
70
- * Result returned by `useLazyRead` hook.
71
- *
72
- * @template TData - The response data type
73
- * @template TError - The error type
74
- * @template TOptions - The trigger options type
75
- */
76
- type BaseLazyReadResult<TData, TError, TOptions> = {
77
- /** Execute the fetch with optional options */
78
- trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
79
- /** True while the fetch is in progress */
80
- loading: boolean;
81
- /** Response data from the API */
82
- data: TData | undefined;
83
- /** Error from the last failed request */
84
- error: TError | undefined;
85
- /** Abort the current fetch */
86
- abort: () => void;
87
- };
88
76
  type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
89
77
  query?: Exclude<TQuery, undefined>;
90
78
  } : {
@@ -123,7 +111,6 @@ type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResp
123
111
  error: infer E;
124
112
  } ? E : unknown : unknown;
125
113
  type ExtractMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] : never;
126
- type ExtractCoreMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "params" | "body">> : object : object;
127
114
  type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
128
115
  query: infer Q;
129
116
  } ? Q : never;
@@ -147,6 +134,33 @@ type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
147
134
  params: Record<infer K, unknown>;
148
135
  };
149
136
  } ? K extends string ? K : never : never;
137
+ type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
138
+ type ExtractInputFromResponse<T> = T extends {
139
+ input: infer I;
140
+ } ? I : never;
141
+ type ExtractTriggerQuery<I> = I extends {
142
+ query: infer Q;
143
+ } ? {
144
+ query?: Q;
145
+ } : unknown;
146
+ type ExtractTriggerBody<I> = I extends {
147
+ body: infer B;
148
+ } ? {
149
+ body?: B;
150
+ } : unknown;
151
+ type ExtractTriggerParams<I> = I extends {
152
+ params: infer P;
153
+ } ? {
154
+ params?: P;
155
+ } : unknown;
156
+ type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? {
157
+ force?: boolean;
158
+ } : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> & {
159
+ /** Force refetch even if data is cached */
160
+ force?: boolean;
161
+ } : {
162
+ force?: boolean;
163
+ };
150
164
  type QueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
151
165
  query?: Exclude<TQuery, undefined>;
152
166
  } : {
@@ -269,21 +283,12 @@ type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
269
283
  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>>;
270
284
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
271
285
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
272
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
273
- data?: unknown;
274
- error?: unknown;
275
- }>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<MergePluginOptions<TPlugins>["read"], ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
276
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
277
- data?: unknown;
278
- error?: unknown;
279
- }>>(readFn: TReadFn): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, MergePluginResults<TPlugins>["read"]> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
286
+ <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<MergePluginOptions<TPlugins>["read"], ResolverContext<TSchema, ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>, TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
287
+ <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>>(readFn: TReadFn): BaseReadResult<ExtractMethodData<TReadFn>, InferError<ExtractMethodError<TReadFn>, TDefaultError>, MergePluginResults<TPlugins>["read"], TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
280
288
  };
281
289
  type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
282
290
  <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>, MergePluginResults<TPlugins>["write"]> & WriteResponseInputFields<ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod>>;
283
291
  };
284
- type UseLazyReadFn<TDefaultError, TSchema> = {
285
- <TMethod extends (...args: never) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod): BaseLazyReadResult<ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractCoreMethodOptions<TMethod>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
286
- };
287
292
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
288
293
  query: infer Q;
289
294
  } ? Q : never, TRequest extends {
@@ -336,23 +341,6 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
336
341
  * ```
337
342
  */
338
343
  useWrite: UseWriteFn<TDefaultError, TSchema, TPlugins>;
339
- /**
340
- * React hook for lazy GET requests with manual triggering (does not auto-fetch on mount).
341
- *
342
- * @param readFn - Function that selects the API endpoint (e.g., `(api) => api("posts").GET`)
343
- * @returns Object containing `trigger`, `data`, `error`, `loading`, and `abort`
344
- *
345
- * @example
346
- * ```tsx
347
- * const { trigger, loading, data } = useLazyRead((api) => api("posts/:id").GET);
348
- *
349
- * const handleClick = async (id) => {
350
- * const { data, error } = await trigger({ params: { id } });
351
- * if (data) console.log('Fetched:', data);
352
- * };
353
- * ```
354
- */
355
- useLazyRead: UseLazyReadFn<TDefaultError, TSchema>;
356
344
  /**
357
345
  * React hook for infinite/paginated data fetching with automatic pagination control.
358
346
  *
@@ -416,40 +404,33 @@ type SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins> = {
416
404
  */
417
405
  declare function createReactSpoosh<TSchema, TDefaultError, TPlugins extends PluginArray, TApi>(instance: SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins>): SpooshReactHooks<TDefaultError, TSchema, TPlugins>;
418
406
 
419
- declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): {
420
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
421
- data?: unknown;
422
- error?: unknown;
423
- }>, TReadOpts>(readFn: TReadFn, readOptions: TReadOpts & BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
424
- readOptions: infer R;
425
- } ? 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 {
426
- readOptions: infer R;
427
- } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
428
- data: infer D;
429
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
430
- error: infer E;
431
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
432
- error: infer E;
433
- }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>): BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
434
- data: infer D;
435
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
436
- error: infer E;
437
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
438
- error: infer E;
439
- }> ? E : unknown, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
440
- <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<{
441
- data?: unknown;
442
- error?: unknown;
443
- }>>(readFn: TReadFn): BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
444
- data: infer D;
445
- }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
446
- error: infer E;
447
- }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
448
- error: infer E;
449
- }> ? E : unknown, MergePluginResults<TPlugins>["read"]> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
450
- };
451
-
452
- declare function createUseLazyRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod) => BaseLazyReadResult<ExtractMethodData<TMethod>, [ExtractMethodError<TMethod>] extends [unknown] ? TDefaultError : ExtractMethodError<TMethod>, ExtractCoreMethodOptions<TMethod>> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
407
+ declare function createUseRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TReadOpts extends BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
408
+ readOptions: infer R;
409
+ } ? 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 {
410
+ readOptions: infer R;
411
+ } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
412
+ data: infer D;
413
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
414
+ error: infer E;
415
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
416
+ error: infer E;
417
+ }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>> = BaseReadOptions & ResolveTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
418
+ readOptions: infer R;
419
+ } ? R : 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 extends PluginTypeConfig> ? Types extends {
420
+ readOptions: infer R;
421
+ } ? R : object : object : never : never) ? T_4 extends unknown ? (x: T_4) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: unknown[]) => Promise<{
422
+ data: infer D;
423
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
424
+ error: infer E;
425
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
426
+ error: infer E;
427
+ }> ? E : unknown, ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn> extends never ? never : Record<ExtractResponseParamNames<TReadFn>, string | number>>>>(readFn: TReadFn, readOptions?: TReadOpts) => BaseReadResult<TReadFn extends (...args: unknown[]) => Promise<{
428
+ data: infer D;
429
+ }> ? D : unknown, [TReadFn extends (...args: unknown[]) => Promise<{
430
+ error: infer E;
431
+ }> ? E : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: unknown[]) => Promise<{
432
+ error: infer E;
433
+ }> ? E : unknown, ResolveResultTypes<MergePluginResults<TPlugins>["read"], TReadOpts>, TriggerOptions<TReadFn>> & ResponseInputFields<ExtractResponseQuery<TReadFn>, ExtractResponseBody<TReadFn>, ExtractResponseParamNames<TReadFn>>;
453
434
 
454
435
  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> & ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
455
436
  writeOptions: infer W;
@@ -467,4 +448,4 @@ declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends
467
448
  readResult: infer R;
468
449
  } ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never>;
469
450
 
470
- export { type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseLazyReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type PluginHooksConfig, type SpooshReactHooks, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, createReactSpoosh, createUseInfiniteRead, createUseLazyRead, createUseRead, createUseWrite };
451
+ export { type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type PluginHooksConfig, type SpooshReactHooks, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, createReactSpoosh, createUseInfiniteRead, createUseRead, createUseWrite };