authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-30 17:59:52-08:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-30 18:00:25-08:00
loge3d6a4b906d60a10abef5cb9611947b52c979f1a
tree4a4ae27a2c0615f53649fa20b4079d18c781b904
parent9fe44b404d1cfae5e4751ac3ef020ef8da521b1a
signaturebadge-check Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

feat!: disambiguate "data only"


7 files changed, 25 insertions(+), 15 deletions(-)

jsr.json+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1{1{
2 "name": "@clo/react-mutation",2 "name": "@clo/react-mutation",
3 "version": "1.1.0",3 "version": "2.0.0",
4 "exports": {4 "exports": {
5 ".": "./src/mod.ts",5 ".": "./src/mod.ts",
6 "./tanstack-query.ts": "./src/tanstack-query.ts",6 "./tanstack-query.ts": "./src/tanstack-query.ts",
readme.changes.md+6
...@@ -1,5 +1,11 @@...@@ -1,5 +1,11 @@
1# notable changes in React Mutation1# notable changes in React Mutation
22
3## v2
4
5### breaking
6
7- rename `onSuccess` and `onSuccessDataOnly` to `onSuccessUi` and `onSuccessData`.
8
3## v1.19## v1.1
410
5- Add `runAsHeadlessPromise`. The function name is intentionally long to avoid using it, please use `runWithOptions` instead.11- Add `runAsHeadlessPromise`. The function name is intentionally long to avoid using it, please use `runWithOptions` instead.
src/mutation.ts+7-7
...@@ -273,13 +273,13 @@ export class BlockingMutation<...@@ -273,13 +273,13 @@ export class BlockingMutation<
273 }273 }
274274
275 const args = array.slice() as Args;275 const args = array.slice() as Args;
276 const { onSuccess, onSuccessDataOnly, onError, onSettled, onRestore } = args276 const { onSuccessUi: onSuccess, onSuccessData, onError, onSettled, onRestore } = args
277 .pop() as RunOptions<Result>;277 .pop() as RunOptions<Result>;
278 const promise = this.#runWithOptions(args, onRestore, true);278 const promise = this.#runWithOptions(args, onRestore, true);
279 return promise.then((result) => {279 return promise.then((result) => {
280 // Call user handlers280 // Call user handlers
281 onSuccess?.(result);281 onSuccess?.(result);
282 onSuccessDataOnly?.(result);282 onSuccessData?.(result);
283 onSettled?.({ status: "success", result });283 onSettled?.({ status: "success", result });
284 return result;284 return result;
285 }).catch((caught: unknown) => {285 }).catch((caught: unknown) => {
...@@ -305,17 +305,17 @@ export class BlockingMutation<...@@ -305,17 +305,17 @@ export class BlockingMutation<
305 }305 }
306306
307 const args = array.slice() as Args;307 const args = array.slice() as Args;
308 const { onSuccess, onSuccessDataOnly, onError, onSettled, onRestore } = args308 const { onSuccessUi, onSuccessData, onError, onSettled, onRestore } = args
309 .pop() as RunOptions<Result>;309 .pop() as RunOptions<Result>;
310 const suppressAll = this.#options.debounceMs !== undefined && !onSuccess && !onError;310 const suppressAll = this.#options.debounceMs !== undefined && !onSuccessUi && !onError;
311 const suppressGlobalSuccess = onSuccess !== undefined || suppressAll;311 const suppressGlobalSuccess = onSuccessUi !== undefined || suppressAll;
312 const suppressGlobalError = onError !== undefined || suppressAll;312 const suppressGlobalError = onError !== undefined || suppressAll;
313313
314 const promise = this.#runWithOptions(args, onRestore, suppressAll);314 const promise = this.#runWithOptions(args, onRestore, suppressAll);
315 promise.then((result) => {315 promise.then((result) => {
316 // Call user handlers316 // Call user handlers
317 onSuccess?.(result);317 onSuccessUi?.(result);
318 onSuccessDataOnly?.(result);318 onSuccessData?.(result);
319 onSettled?.({ status: "success", result });319 onSettled?.({ status: "success", result });
320320
321 // Call global handler unless suppressed321 // Call global handler unless suppressed
src/react.ts+1-1
...@@ -261,7 +261,7 @@ class Observer<Args extends unknown[], Result> {...@@ -261,7 +261,7 @@ class Observer<Args extends unknown[], Result> {
261 const promise = mutation.runWithOptions(261 const promise = mutation.runWithOptions(
262 ...args,262 ...args,
263 {263 {
264 onSuccess: watchesSuccess ? () => {} : undefined,264 onSuccessUi: watchesSuccess ? () => {} : undefined,
265 onError: watchesError ? () => {} : undefined,265 onError: watchesError ? () => {} : undefined,
266 // For debounced mutations, suppress global handlers in runWithOptions266 // For debounced mutations, suppress global handlers in runWithOptions
267 // The debounce logic (#enqueueDebouncedCall) will call them once if needed267 // The debounce logic (#enqueueDebouncedCall) will call them once if needed
src/types.ts+8-4
...@@ -29,10 +29,14 @@ export interface Mutation<Args extends unknown[], Result> {...@@ -29,10 +29,14 @@ export interface Mutation<Args extends unknown[], Result> {
29}29}
3030
31export interface RunOptions<Result> {31export interface RunOptions<Result> {
32 /** Called on success, suppresses the global success handler */32 /** Called to show the success UI. Passing this suppresses the global success handler. */
33 onSuccess?: (result: Result) => void;33 onSuccessUi?: (result: Result) => void;
34 /** Called on success, does NOT suppress the global success handler */34 /**
35 onSuccessDataOnly?: (result: Result) => void;35 * Called with result data, but unlike `onSuccessUi`, this indicates the
36 * caller is not concerned with the UI flow of the success. Passing this
37 * does NOT suppress the global success handler.
38 */
39 onSuccessData?: (result: Result) => void;
36 /** Called on error, suppresses the global error handler */40 /** Called on error, suppresses the global error handler */
37 onError?: (error: unknown) => void;41 onError?: (error: unknown) => void;
38 /** Called on settled (doesn't suppress global handlers) */42 /** Called on settled (doesn't suppress global handlers) */
test/ordering.test.ts+1-1
...@@ -378,7 +378,7 @@ test("runWithOptions callbacks: onSuccess called before global handler", async (...@@ -378,7 +378,7 @@ test("runWithOptions callbacks: onSuccess called before global handler", async (
378 });378 });
379379
380 mutTest.runWithOptions({380 mutTest.runWithOptions({
381 onSuccess: () => {381 onSuccessUi: () => {
382 calls.push("onSuccess");382 calls.push("onSuccess");
383 },383 },
384 onSettled: () => {384 onSettled: () => {
test/runWithOptions.test.tsx+1-1
...@@ -32,7 +32,7 @@ test("runWithOptions should allow react hook to do local handling", async () =>...@@ -32,7 +32,7 @@ test("runWithOptions should allow react hook to do local handling", async () =>
32 <button32 <button
33 data-testid="a"33 data-testid="a"
34 onClick={() => {34 onClick={() => {
35 runWithOptions({ onSuccessDataOnly: () => {} });35 runWithOptions({ onSuccessData: () => {} });
36 }}36 }}
37 >37 >
38 button38 button