@spoosh/react 0.9.0 → 0.10.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
@@ -69,7 +69,7 @@ Trigger mutations with loading and error states.
69
69
  ```typescript
70
70
  function CreateUser() {
71
71
  const { trigger, loading, error } = useWrite(
72
- (api) => api("users").POST
72
+ (api) => api("users").POST()
73
73
  );
74
74
 
75
75
  const handleSubmit = async (data: CreateUserBody) => {
@@ -90,7 +90,7 @@ function CreateUser() {
90
90
  }
91
91
 
92
92
  // With path parameters
93
- const updateUser = useWrite((api) => api("users/:id").PUT);
93
+ const updateUser = useWrite((api) => api("users/:id").PUT());
94
94
 
95
95
  await updateUser.trigger({
96
96
  params: { id: userId },
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteClient, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
1
+ import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteSelectorClient, SpooshBody, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
2
2
 
3
3
  type SuccessResponse<T> = Extract<T, {
4
4
  data: unknown;
@@ -81,28 +81,28 @@ type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
81
81
  ] extends [never, never, never] ? object : {
82
82
  input: ReadInputFields<TQuery, TBody, TParamNames>;
83
83
  };
84
- type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
85
- type ExtractInputFromResponse<T> = T extends {
84
+ type TriggerAwaitedReturn$1<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
85
+ type ExtractInputFromResponse$1<T> = T extends {
86
86
  input: infer I;
87
87
  } ? I : never;
88
- type ExtractTriggerQuery<I> = I extends {
88
+ type ExtractTriggerQuery$1<I> = I extends {
89
89
  query: infer Q;
90
90
  } ? {
91
91
  query?: Q;
92
92
  } : unknown;
93
- type ExtractTriggerBody<I> = I extends {
93
+ type ExtractTriggerBody$1<I> = I extends {
94
94
  body: infer B;
95
95
  } ? {
96
96
  body?: B;
97
97
  } : unknown;
98
- type ExtractTriggerParams<I> = I extends {
98
+ type ExtractTriggerParams$1<I> = I extends {
99
99
  params: infer P;
100
100
  } ? {
101
101
  params?: P;
102
102
  } : unknown;
103
- type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? {
103
+ type TriggerOptions<T> = ExtractInputFromResponse$1<TriggerAwaitedReturn$1<T>> extends infer I ? [I] extends [never] ? {
104
104
  force?: boolean;
105
- } : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> & {
105
+ } : ExtractTriggerQuery$1<I> & ExtractTriggerBody$1<I> & ExtractTriggerParams$1<I> & {
106
106
  /** Force refetch even if data is cached */
107
107
  force?: boolean;
108
108
  } : {
@@ -160,6 +160,30 @@ type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField
160
160
  type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
161
161
  input: InputFields<TQuery, TBody, TParamNames> | undefined;
162
162
  };
163
+ type TriggerAwaitedReturn<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
164
+ type ExtractInputFromResponse<T> = T extends {
165
+ input: infer I;
166
+ } ? I : never;
167
+ type ExtractTriggerQuery<I> = I extends {
168
+ query: infer Q;
169
+ } ? undefined extends Q ? {
170
+ query?: Exclude<Q, undefined>;
171
+ } : {
172
+ query: Q;
173
+ } : unknown;
174
+ type ExtractTriggerBody<I> = I extends {
175
+ body: infer B;
176
+ } ? undefined extends B ? {
177
+ body?: Exclude<B, undefined> | SpooshBody<Exclude<B, undefined>>;
178
+ } : {
179
+ body: B | SpooshBody<B>;
180
+ } : unknown;
181
+ type ExtractTriggerParams<I> = I extends {
182
+ params: infer P;
183
+ } ? {
184
+ params: P;
185
+ } : unknown;
186
+ type WriteTriggerInput<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? object : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> : object;
163
187
  /**
164
188
  * Result returned by `useWrite` hook.
165
189
  *
@@ -183,7 +207,7 @@ type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> =
183
207
  abort: () => void;
184
208
  };
185
209
  type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
186
- type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
210
+ type WriteApiClient<TSchema, TDefaultError> = WriteSelectorClient<TSchema, TDefaultError>;
187
211
 
188
212
  type TagModeInArray = "all" | "self";
189
213
  type AnyInfiniteRequestOptions = {
@@ -286,12 +310,13 @@ type InfiniteReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaul
286
310
  type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
287
311
  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>>;
288
312
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
313
+ type ResolvedWriteTriggerOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["writeTrigger"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
289
314
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
290
315
  <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>>;
291
316
  <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>>;
292
317
  };
293
318
  type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
294
- <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>>;
319
+ <TWriteFn extends (api: WriteApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TWriteOpts extends ResolvedWriteOptions<TSchema, TPlugins, TWriteFn, TDefaultError> = ResolvedWriteOptions<TSchema, TPlugins, TWriteFn, TDefaultError>>(writeFn: TWriteFn, writeOptions?: TWriteOpts): BaseWriteResult<ExtractMethodData<TWriteFn>, InferError<ExtractMethodError<TWriteFn>, TDefaultError>, WriteTriggerInput<TWriteFn> & ResolvedWriteTriggerOptions<TSchema, TPlugins, TWriteFn, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["write"], TWriteOpts>> & WriteResponseInputFields<ExtractMethodQuery<TWriteFn>, ExtractMethodBody<TWriteFn>, ExtractResponseParamNames<TWriteFn>>;
295
320
  };
296
321
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
297
322
  query: infer Q;
@@ -331,12 +356,12 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
331
356
  /**
332
357
  * React hook for mutations (POST, PUT, PATCH, DELETE) with manual triggering.
333
358
  *
334
- * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST`)
359
+ * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST()`)
335
360
  * @returns Object containing `trigger`, `data`, `error`, `loading`, and `abort`
336
361
  *
337
362
  * @example
338
363
  * ```tsx
339
- * const { trigger, loading, data } = useWrite((api) => api("posts").POST);
364
+ * const { trigger, loading, data } = useWrite((api) => api("posts").POST());
340
365
  *
341
366
  * const handleSubmit = async (formData) => {
342
367
  * const { data, error } = await trigger({ body: formData });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteClient, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
1
+ import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteSelectorClient, SpooshBody, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
2
2
 
3
3
  type SuccessResponse<T> = Extract<T, {
4
4
  data: unknown;
@@ -81,28 +81,28 @@ type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
81
81
  ] extends [never, never, never] ? object : {
82
82
  input: ReadInputFields<TQuery, TBody, TParamNames>;
83
83
  };
84
- type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
85
- type ExtractInputFromResponse<T> = T extends {
84
+ type TriggerAwaitedReturn$1<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
85
+ type ExtractInputFromResponse$1<T> = T extends {
86
86
  input: infer I;
87
87
  } ? I : never;
88
- type ExtractTriggerQuery<I> = I extends {
88
+ type ExtractTriggerQuery$1<I> = I extends {
89
89
  query: infer Q;
90
90
  } ? {
91
91
  query?: Q;
92
92
  } : unknown;
93
- type ExtractTriggerBody<I> = I extends {
93
+ type ExtractTriggerBody$1<I> = I extends {
94
94
  body: infer B;
95
95
  } ? {
96
96
  body?: B;
97
97
  } : unknown;
98
- type ExtractTriggerParams<I> = I extends {
98
+ type ExtractTriggerParams$1<I> = I extends {
99
99
  params: infer P;
100
100
  } ? {
101
101
  params?: P;
102
102
  } : unknown;
103
- type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? {
103
+ type TriggerOptions<T> = ExtractInputFromResponse$1<TriggerAwaitedReturn$1<T>> extends infer I ? [I] extends [never] ? {
104
104
  force?: boolean;
105
- } : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> & {
105
+ } : ExtractTriggerQuery$1<I> & ExtractTriggerBody$1<I> & ExtractTriggerParams$1<I> & {
106
106
  /** Force refetch even if data is cached */
107
107
  force?: boolean;
108
108
  } : {
@@ -160,6 +160,30 @@ type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField
160
160
  type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
161
161
  input: InputFields<TQuery, TBody, TParamNames> | undefined;
162
162
  };
163
+ type TriggerAwaitedReturn<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
164
+ type ExtractInputFromResponse<T> = T extends {
165
+ input: infer I;
166
+ } ? I : never;
167
+ type ExtractTriggerQuery<I> = I extends {
168
+ query: infer Q;
169
+ } ? undefined extends Q ? {
170
+ query?: Exclude<Q, undefined>;
171
+ } : {
172
+ query: Q;
173
+ } : unknown;
174
+ type ExtractTriggerBody<I> = I extends {
175
+ body: infer B;
176
+ } ? undefined extends B ? {
177
+ body?: Exclude<B, undefined> | SpooshBody<Exclude<B, undefined>>;
178
+ } : {
179
+ body: B | SpooshBody<B>;
180
+ } : unknown;
181
+ type ExtractTriggerParams<I> = I extends {
182
+ params: infer P;
183
+ } ? {
184
+ params: P;
185
+ } : unknown;
186
+ type WriteTriggerInput<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? object : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> : object;
163
187
  /**
164
188
  * Result returned by `useWrite` hook.
165
189
  *
@@ -183,7 +207,7 @@ type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> =
183
207
  abort: () => void;
184
208
  };
185
209
  type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
186
- type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
210
+ type WriteApiClient<TSchema, TDefaultError> = WriteSelectorClient<TSchema, TDefaultError>;
187
211
 
188
212
  type TagModeInArray = "all" | "self";
189
213
  type AnyInfiniteRequestOptions = {
@@ -286,12 +310,13 @@ type InfiniteReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaul
286
310
  type InferError<T, TDefaultError> = [T] extends [unknown] ? TDefaultError : T;
287
311
  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>>;
288
312
  type ResolvedWriteOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["write"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
313
+ type ResolvedWriteTriggerOptions<TSchema, TPlugins extends PluginArray, TMethod, TDefaultError> = ResolveTypes<MergePluginOptions<TPlugins>["writeTrigger"], WriteResolverContext<TSchema, TMethod, TDefaultError>>;
289
314
  type UseReadFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
290
315
  <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>>;
291
316
  <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>>;
292
317
  };
293
318
  type UseWriteFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
294
- <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>>;
319
+ <TWriteFn extends (api: WriteApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TWriteOpts extends ResolvedWriteOptions<TSchema, TPlugins, TWriteFn, TDefaultError> = ResolvedWriteOptions<TSchema, TPlugins, TWriteFn, TDefaultError>>(writeFn: TWriteFn, writeOptions?: TWriteOpts): BaseWriteResult<ExtractMethodData<TWriteFn>, InferError<ExtractMethodError<TWriteFn>, TDefaultError>, WriteTriggerInput<TWriteFn> & ResolvedWriteTriggerOptions<TSchema, TPlugins, TWriteFn, TDefaultError>, ResolveResultTypes<MergePluginResults<TPlugins>["write"], TWriteOpts>> & WriteResponseInputFields<ExtractMethodQuery<TWriteFn>, ExtractMethodBody<TWriteFn>, ExtractResponseParamNames<TWriteFn>>;
295
320
  };
296
321
  type InfiniteReadResolverContext<TSchema, TData, TError, TRequest> = ResolverContext<TSchema, TData, TError, TRequest extends {
297
322
  query: infer Q;
@@ -331,12 +356,12 @@ type SpooshReactHooks<TDefaultError, TSchema, TPlugins extends PluginArray> = {
331
356
  /**
332
357
  * React hook for mutations (POST, PUT, PATCH, DELETE) with manual triggering.
333
358
  *
334
- * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST`)
359
+ * @param writeFn - Function that selects the API endpoint (e.g., `(api) => api("posts").POST()`)
335
360
  * @returns Object containing `trigger`, `data`, `error`, `loading`, and `abort`
336
361
  *
337
362
  * @example
338
363
  * ```tsx
339
- * const { trigger, loading, data } = useWrite((api) => api("posts").POST);
364
+ * const { trigger, loading, data } = useWrite((api) => api("posts").POST());
340
365
  *
341
366
  * const handleSubmit = async (formData) => {
342
367
  * const { data, error } = await trigger({ body: formData });
package/dist/index.js CHANGED
@@ -112,7 +112,7 @@ function createUseRead(options) {
112
112
  const tagsKey = JSON.stringify(tags);
113
113
  const executeWithTracking = (0, import_react.useCallback)(
114
114
  async (force = false, overrideOptions) => {
115
- setRequestState((prev) => ({ ...prev, isPending: true }));
115
+ setRequestState({ isPending: true, error: void 0 });
116
116
  try {
117
117
  const execOptions = overrideOptions ? { ...capturedCall.options ?? {}, ...overrideOptions } : void 0;
118
118
  const response = await controller.execute(execOptions, { force });
@@ -226,7 +226,7 @@ function createUseRead(options) {
226
226
  };
227
227
  forceUpdate((n) => n + 1);
228
228
  newController.mount();
229
- setRequestState((prev) => ({ ...prev, isPending: true }));
229
+ setRequestState({ isPending: true, error: void 0 });
230
230
  try {
231
231
  const response = await newController.execute(mergedOptions, {
232
232
  force
@@ -294,7 +294,7 @@ var import_react2 = require("react");
294
294
  var import_core2 = require("@spoosh/core");
295
295
  function createUseWrite(options) {
296
296
  const { api, stateManager, pluginExecutor, eventEmitter } = options;
297
- function useWrite(writeFn) {
297
+ function useWrite(writeFn, writeOptions) {
298
298
  const instanceId = (0, import_react2.useId)();
299
299
  const selectorResultRef = (0, import_react2.useRef)({
300
300
  call: null,
@@ -304,16 +304,16 @@ function createUseWrite(options) {
304
304
  selectorResultRef.current = result;
305
305
  });
306
306
  writeFn(selectorProxy);
307
- const selectedEndpoint = selectorResultRef.current.selector;
308
- if (!selectedEndpoint) {
307
+ const capturedCall = selectorResultRef.current.call;
308
+ if (!capturedCall) {
309
309
  throw new Error(
310
- 'useWrite requires selecting an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST)'
310
+ 'useWrite requires calling an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST())'
311
311
  );
312
312
  }
313
- const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
313
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
314
314
  const queryKey = stateManager.createQueryKey({
315
- path: selectedEndpoint.path,
316
- method: selectedEndpoint.method,
315
+ path: capturedCall.path,
316
+ method: capturedCall.method,
317
317
  options: void 0
318
318
  });
319
319
  const controllerRef = (0, import_react2.useRef)(null);
@@ -321,16 +321,16 @@ function createUseWrite(options) {
321
321
  controllerRef.current = {
322
322
  controller: (0, import_core2.createOperationController)({
323
323
  operationType: "write",
324
- path: selectedEndpoint.path,
325
- method: selectedEndpoint.method,
324
+ path: capturedCall.path,
325
+ method: capturedCall.method,
326
326
  tags: [],
327
327
  stateManager,
328
328
  eventEmitter,
329
329
  pluginExecutor,
330
330
  instanceId,
331
331
  fetchFn: async (fetchOpts) => {
332
- const pathMethods = api(selectedEndpoint.path);
333
- const method = pathMethods[selectedEndpoint.method];
332
+ const pathMethods = api(capturedCall.path);
333
+ const method = pathMethods[capturedCall.method];
334
334
  return method(fetchOpts);
335
335
  }
336
336
  }),
@@ -351,11 +351,12 @@ function createUseWrite(options) {
351
351
  const trigger = (0, import_react2.useCallback)(
352
352
  async (triggerOptions) => {
353
353
  setLastTriggerOptions(triggerOptions);
354
- setRequestState((prev) => ({ ...prev, isPending: true }));
354
+ setRequestState({ isPending: true, error: void 0 });
355
355
  const params = triggerOptions?.params;
356
356
  const resolvedPath = (0, import_core2.resolvePath)(pathSegments, params);
357
357
  const tags = (0, import_core2.resolveTags)(triggerOptions, resolvedPath);
358
- controller.setPluginOptions({ ...triggerOptions, tags });
358
+ const mergedOptions = { ...writeOptions, ...triggerOptions, tags };
359
+ controller.setPluginOptions(mergedOptions);
359
360
  try {
360
361
  const response = await controller.execute(triggerOptions, {
361
362
  force: true
@@ -371,7 +372,7 @@ function createUseWrite(options) {
371
372
  return { error: err };
372
373
  }
373
374
  },
374
- [selectedEndpoint.path]
375
+ [capturedCall.path]
375
376
  );
376
377
  const entry = stateManager.getCache(queryKey);
377
378
  const pluginResultData = entry?.meta ? Object.fromEntries(entry.meta) : {};
package/dist/index.mjs CHANGED
@@ -99,7 +99,7 @@ function createUseRead(options) {
99
99
  const tagsKey = JSON.stringify(tags);
100
100
  const executeWithTracking = useCallback(
101
101
  async (force = false, overrideOptions) => {
102
- setRequestState((prev) => ({ ...prev, isPending: true }));
102
+ setRequestState({ isPending: true, error: void 0 });
103
103
  try {
104
104
  const execOptions = overrideOptions ? { ...capturedCall.options ?? {}, ...overrideOptions } : void 0;
105
105
  const response = await controller.execute(execOptions, { force });
@@ -213,7 +213,7 @@ function createUseRead(options) {
213
213
  };
214
214
  forceUpdate((n) => n + 1);
215
215
  newController.mount();
216
- setRequestState((prev) => ({ ...prev, isPending: true }));
216
+ setRequestState({ isPending: true, error: void 0 });
217
217
  try {
218
218
  const response = await newController.execute(mergedOptions, {
219
219
  force
@@ -292,7 +292,7 @@ import {
292
292
  } from "@spoosh/core";
293
293
  function createUseWrite(options) {
294
294
  const { api, stateManager, pluginExecutor, eventEmitter } = options;
295
- function useWrite(writeFn) {
295
+ function useWrite(writeFn, writeOptions) {
296
296
  const instanceId = useId2();
297
297
  const selectorResultRef = useRef2({
298
298
  call: null,
@@ -302,16 +302,16 @@ function createUseWrite(options) {
302
302
  selectorResultRef.current = result;
303
303
  });
304
304
  writeFn(selectorProxy);
305
- const selectedEndpoint = selectorResultRef.current.selector;
306
- if (!selectedEndpoint) {
305
+ const capturedCall = selectorResultRef.current.call;
306
+ if (!capturedCall) {
307
307
  throw new Error(
308
- 'useWrite requires selecting an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST)'
308
+ 'useWrite requires calling an HTTP method (POST, PUT, PATCH, DELETE). Example: useWrite((api) => api("posts").POST())'
309
309
  );
310
310
  }
311
- const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
311
+ const pathSegments = capturedCall.path.split("/").filter(Boolean);
312
312
  const queryKey = stateManager.createQueryKey({
313
- path: selectedEndpoint.path,
314
- method: selectedEndpoint.method,
313
+ path: capturedCall.path,
314
+ method: capturedCall.method,
315
315
  options: void 0
316
316
  });
317
317
  const controllerRef = useRef2(null);
@@ -319,16 +319,16 @@ function createUseWrite(options) {
319
319
  controllerRef.current = {
320
320
  controller: createOperationController2({
321
321
  operationType: "write",
322
- path: selectedEndpoint.path,
323
- method: selectedEndpoint.method,
322
+ path: capturedCall.path,
323
+ method: capturedCall.method,
324
324
  tags: [],
325
325
  stateManager,
326
326
  eventEmitter,
327
327
  pluginExecutor,
328
328
  instanceId,
329
329
  fetchFn: async (fetchOpts) => {
330
- const pathMethods = api(selectedEndpoint.path);
331
- const method = pathMethods[selectedEndpoint.method];
330
+ const pathMethods = api(capturedCall.path);
331
+ const method = pathMethods[capturedCall.method];
332
332
  return method(fetchOpts);
333
333
  }
334
334
  }),
@@ -349,11 +349,12 @@ function createUseWrite(options) {
349
349
  const trigger = useCallback2(
350
350
  async (triggerOptions) => {
351
351
  setLastTriggerOptions(triggerOptions);
352
- setRequestState((prev) => ({ ...prev, isPending: true }));
352
+ setRequestState({ isPending: true, error: void 0 });
353
353
  const params = triggerOptions?.params;
354
354
  const resolvedPath = resolvePath2(pathSegments, params);
355
355
  const tags = resolveTags2(triggerOptions, resolvedPath);
356
- controller.setPluginOptions({ ...triggerOptions, tags });
356
+ const mergedOptions = { ...writeOptions, ...triggerOptions, tags };
357
+ controller.setPluginOptions(mergedOptions);
357
358
  try {
358
359
  const response = await controller.execute(triggerOptions, {
359
360
  force: true
@@ -369,7 +370,7 @@ function createUseWrite(options) {
369
370
  return { error: err };
370
371
  }
371
372
  },
372
- [selectedEndpoint.path]
373
+ [capturedCall.path]
373
374
  );
374
375
  const entry = stateManager.getCache(queryKey);
375
376
  const pluginResultData = entry?.meta ? Object.fromEntries(entry.meta) : {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/react",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "license": "MIT",
5
5
  "description": "React hooks for Spoosh API toolkit",
6
6
  "keywords": [
@@ -34,13 +34,13 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "@spoosh/core": ">=0.13.0",
37
+ "@spoosh/core": ">=0.13.2",
38
38
  "react": "^18 || ^19"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@testing-library/react": "^16.0.0",
42
42
  "jsdom": "^26.0.0",
43
- "@spoosh/core": "0.13.0",
43
+ "@spoosh/core": "0.13.2",
44
44
  "@spoosh/test-utils": "0.2.0"
45
45
  },
46
46
  "scripts": {