authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-28 17:35:45-08:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-01-28 18:51:56-08:00
log2486cbb9d095be3d97251f02f076d0e2a1cb0033
tree07dc76904411d15ae8b97c3c862fb3b074afcd24
parentc6028dcd497631ff2d5a5a6c24b74b41f3ad21f4
signaturelock-open Commit is signed but in an unrecognized format.

fix: bring back the success message


5 files changed, 22 insertions(+), 13 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.0.0-beta.3",3 "version": "1.0.0-beta.4",
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.md+3-3
...@@ -14,7 +14,7 @@ The primary gains React Mutation provides are...@@ -14,7 +14,7 @@ The primary gains React Mutation provides are
14 `isError`, unhandled errors will be propagated to a global handler, which can14 `isError`, unhandled errors will be propagated to a global handler, which can
15 display a UI toast. Otherwise, the component can display the error locally.15 display a UI toast. Otherwise, the component can display the error locally.
16- Optimistic helpers allow defining rollbacks and refetching logic independant16- Optimistic helpers allow defining rollbacks and refetching logic independant
17 of the actual mutation. The [built in helpers for React Query](#React-Query-Optimistic-Helpers) show this power in more detail.17 of the actual mutation. The [built in helpers for React Query](#react-query-optimistic-helpers) show this power in more detail.
18- Debounced Mutations are just so awesome to use.18- Debounced Mutations are just so awesome to use.
1919
20## Usage20## Usage
...@@ -22,11 +22,11 @@ The primary gains React Mutation provides are...@@ -22,11 +22,11 @@ The primary gains React Mutation provides are
22This library declares two kinds of mutations. Each kind has different behavior22This library declares two kinds of mutations. Each kind has different behavior
23around concurrent operations.23around concurrent operations.
2424
25- [**Blocking Mutations**](#Blocking-Mutations): A mutation blocks the UI until it25- [**Blocking Mutations**](#blocking-mutations): A mutation blocks the UI until it
26 is complete. You press a button, a pending state appears, then it completes.26 is complete. You press a button, a pending state appears, then it completes.
27 This works great for forms, creations and deletions, and is similar to React27 This works great for forms, creations and deletions, and is similar to React
28 Query's mutation system.28 Query's mutation system.
29- [**Debounced Mutations**](#Debounced-Mutations): Each call to the mutation applies29- [**Debounced Mutations**](#debounced-mutations): Each call to the mutation applies
30 new optimistic state, and after a debounce (or throttle) the new optimistic30 new optimistic state, and after a debounce (or throttle) the new optimistic
31 state is committed to the API. UI never shows a pending state for these.31 state is committed to the API. UI never shows a pending state for these.
32 This works great for auto-saving input fields, follow buttons, and is32 This works great for auto-saving input fields, follow buttons, and is
src/blocking.ts+3-2
...@@ -34,7 +34,7 @@ export interface BlockingMutationOptions<...@@ -34,7 +34,7 @@ export interface BlockingMutationOptions<
34 * Used in success messages.34 * Used in success messages.
35 * Phrase it as a complete success message, e.g., "Deleted item successfully"35 * Phrase it as a complete success message, e.g., "Deleted item successfully"
36 */36 */
37 describeResult: string | ((context: Config["context"] & { args: Args; result: Result }) => string);37 describeResult: string | ((context: Config["context"] & { args: Args; result: Result }) => string) | null;
38 /**38 /**
39 * Specifying the optimistic strategy is required. To disable, pass an empty39 * Specifying the optimistic strategy is required. To disable, pass an empty
40 * function with a comment to document why it isn't needed.40 * function with a comment to document why it isn't needed.
...@@ -169,8 +169,9 @@ export class BlockingMutation<...@@ -169,8 +169,9 @@ export class BlockingMutation<
169 : describe;169 : describe;
170 }170 }
171171
172 describeResult(args: Args, result: Result): string {172 describeResult(args: Args, result: Result): string | undefined {
173 const { describeResult } = this.#options;173 const { describeResult } = this.#options;
174 if (describeResult === null) return undefined;
174 return typeof describeResult === "function"175 return typeof describeResult === "function"
175 ? describeResult({ ...this.#client.context, args, result })176 ? describeResult({ ...this.#client.context, args, result })
176 : describeResult;177 : describeResult;
src/debounced.ts+14-6
...@@ -14,7 +14,10 @@ export interface DebouncedMutationOptions<...@@ -14,7 +14,10 @@ export interface DebouncedMutationOptions<
14 * A rest params type is used to allow type inference. Place this function first to14 * A rest params type is used to allow type inference. Place this function first to
15 * ensure TypeScript correctly infers the argument type for the rest of the functions.15 * ensure TypeScript correctly infers the argument type for the rest of the functions.
16 */16 */
17 optimistic: (context: DebouncedOptimisticContext<Config>, ...args: Args) => void;17 optimistic: (
18 context: DebouncedOptimisticContext<Config>,
19 ...args: Args
20 ) => void;
18 /**21 /**
19 * Retrieve the current/optimistic value of the mutation. When this returns22 * Retrieve the current/optimistic value of the mutation. When this returns
20 * the same thing as when the mutation started, it means that `mutate` does23 * the same thing as when the mutation started, it means that `mutate` does
...@@ -56,7 +59,7 @@ export interface DebouncedMutationOptions<...@@ -56,7 +59,7 @@ export interface DebouncedMutationOptions<
56 ) => string);59 ) => string);
57 /**60 /**
58 * Used in success messages.61 * Used in success messages.
59 * Phrase it as a complete success message, e.g., "Renamed item successfully"62 * Phrase it as a complete success message: "Renamed item successfully"
60 */63 */
61 describeResult:64 describeResult:
62 | string65 | string
...@@ -64,7 +67,8 @@ export interface DebouncedMutationOptions<...@@ -64,7 +67,8 @@ export interface DebouncedMutationOptions<
64 context: DebouncedCommitContext<NoInfer<Args>, Optimistic, Config> & {67 context: DebouncedCommitContext<NoInfer<Args>, Optimistic, Config> & {
65 result: Result;68 result: Result;
66 },69 },
67 ) => string);70 ) => string)
71 | null;
68 /**72 /**
69 * Refetch all of the data this mutation could have affected.73 * Refetch all of the data this mutation could have affected.
70 */74 */
...@@ -251,15 +255,16 @@ export class DebouncedMutation<...@@ -251,15 +255,16 @@ export class DebouncedMutation<
251 }255 }
252256
253 // Not available for debounced mutations - success reporting happens during commit257 // Not available for debounced mutations - success reporting happens during commit
254 describeResult: undefined = undefined;258 describeResult: null = null;
255259
256 #describeResult(260 #describeResult(
257 args: Args,261 args: Args,
258 initial: Optimistic,262 initial: Optimistic,
259 current: Optimistic,263 current: Optimistic,
260 result: Result,264 result: Result,
261 ): string {265 ): string | undefined {
262 const { describeResult } = this.#options;266 const { describeResult } = this.#options;
267 if (describeResult === null) return undefined;
263 return typeof describeResult === "function"268 return typeof describeResult === "function"
264 ? describeResult({269 ? describeResult({
265 ...this.#client.context,270 ...this.#client.context,
...@@ -302,7 +307,10 @@ export class DebouncedMutation<...@@ -302,7 +307,10 @@ export class DebouncedMutation<
302307
303 // If this is the first call in the debounced run, take a snapshot and create shared helpers308 // If this is the first call in the debounced run, take a snapshot and create shared helpers
304 if (channel.initial === null) {309 if (channel.initial === null) {
305 channel.initial = this.#options.getValue({ ...this.#client.context, args });310 channel.initial = this.#options.getValue({
311 ...this.#client.context,
312 args,
313 });
306 channel.firstArgs = args;314 channel.firstArgs = args;
307315
308 // Create shared onRefetch handler for the debounced run316 // Create shared onRefetch handler for the debounced run
src/types.ts+1-1
...@@ -14,7 +14,7 @@ export interface Mutation<Args extends unknown[], Result> {...@@ -14,7 +14,7 @@ export interface Mutation<Args extends unknown[], Result> {
14 cb: (update: MutationEvent<Result>) => void,14 cb: (update: MutationEvent<Result>) => void,
15 ): () => void;15 ): () => void;
16 describe(...args: Args): string;16 describe(...args: Args): string;
17 describeResult?: (args: Args, result: Result) => string | undefined;17 describeResult: ((args: Args, result: Result) => string | undefined) | null;
18 client: MutationClient<object, object>;18 client: MutationClient<object, object>;
19}19}
2020