| ... | ... | @@ -112,11 +112,22 @@ interface PendingDebouncedState<Args extends unknown[], Result> { |
| 112 | 112 | shouldCallGlobalHandler: boolean; |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | | /** Wrapper for errors that includes the description captured before rollback */ |
| 116 | | interface MutationError { |
| 117 | | __mutationError: true; |
| 118 | | error: unknown; |
| 119 | | description: string; |
| 115 | /** Internal wrapper that preserves the pre-rollback description for reporting. */ |
| 116 | class MutationError extends Error { |
| 117 | constructor( |
| 118 | readonly error: unknown, |
| 119 | readonly description: string, |
| 120 | ) { |
| 121 | super(errMessage(error), { cause: error }); |
| 122 | this.name = "MutationError"; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | function unwrapMutationError(caught: unknown) { |
| 127 | if (caught instanceof MutationError) { |
| 128 | return { error: caught.error, description: caught.description }; |
| 129 | } |
| 130 | return { error: caught, description: null }; |
| 120 | 131 | } |
| 121 | 132 | |
| 122 | 133 | interface Channel<Args extends unknown[], Result, OptimisticHelpers> { |
| ... | ... | @@ -283,16 +294,12 @@ export class BlockingMutation< |
| 283 | 294 | onSettled?.({ status: "success", result }); |
| 284 | 295 | return result; |
| 285 | 296 | }).catch((caught: unknown) => { |
| 286 | | // Extract error and description if this is a wrapped mutation error |
| 287 | | const isMutationError = (caught as MutationError)?.__mutationError === true; |
| 288 | | const error = isMutationError ? (caught as MutationError).error : caught; |
| 289 | | const description = isMutationError ? (caught as MutationError).description : this.describe(...args); |
| 297 | const { error } = unwrapMutationError(caught); |
| 290 | 298 | |
| 291 | | // Call user handlers with the unwrapped error |
| 292 | 299 | onError?.(error); |
| 293 | 300 | onSettled?.({ status: "error", error }); |
| 294 | 301 | |
| 295 | | throw caught; |
| 302 | throw error; |
| 296 | 303 | }); |
| 297 | 304 | } |
| 298 | 305 | |
| ... | ... | @@ -326,12 +333,8 @@ export class BlockingMutation< |
| 326 | 333 | } |
| 327 | 334 | } |
| 328 | 335 | }).catch((caught: unknown) => { |
| 329 | | // Extract error and description if this is a wrapped mutation error |
| 330 | | const isMutationError = (caught as MutationError)?.__mutationError === true; |
| 331 | | const error = isMutationError ? (caught as MutationError).error : caught; |
| 332 | | const description = isMutationError ? (caught as MutationError).description : this.describe(...args); |
| 336 | const { error, description = this.describe(...args) } = unwrapMutationError(caught); |
| 333 | 337 | |
| 334 | | // Call user handlers with the unwrapped error |
| 335 | 338 | onError?.(error); |
| 336 | 339 | onSettled?.({ status: "error", error }); |
| 337 | 340 | |
| ... | ... | @@ -533,7 +536,7 @@ export class BlockingMutation< |
| 533 | 536 | }, (error) => { |
| 534 | 537 | // Capture description BEFORE rollback so it sees optimistic state |
| 535 | 538 | const description = this.describe(...args); |
| 536 | | const wrappedError: MutationError = { __mutationError: true, error, description }; |
| 539 | const wrappedError = new MutationError(error, description); |
| 537 | 540 | |
| 538 | 541 | // if an error happens, then every rollback is called in reverse order |
| 539 | 542 | let next; |
| ... | ... | @@ -801,10 +804,7 @@ export class BlockingMutation< |
| 801 | 804 | } |
| 802 | 805 | }, |
| 803 | 806 | (caught) => { |
| 804 | | // Extract error and description if this is a wrapped mutation error |
| 805 | | const isMutationError = (caught as MutationError)?.__mutationError === true; |
| 806 | | const error = isMutationError ? (caught as MutationError).error : caught; |
| 807 | | const description = isMutationError ? (caught as MutationError).description : this.describe(...args); |
| 807 | const { error, description = this.describe(...args) } = unwrapMutationError(caught); |
| 808 | 808 | |
| 809 | 809 | // Reject all pending promises with unwrapped error |
| 810 | 810 | pending.forEach((p) => p.reject(error)); |