🐛 Fix AbortAddon ignoring user-provided signals#301
🐛 Fix AbortAddon ignoring user-provided signals#301js62789 wants to merge 3 commits intoelbywan:masterfrom
Conversation
|
Hey @js62789, thanks for the PR.
This seems wrong? The code appear to do the exact opposite. if (!options["signal"]) {
options["signal"] = fetchController.signal
}
|
684a3e8 to
0b90bc4
Compare
|
You’re right, I misspoke earlier. What I meant was something more along the lines of:
I still believe this is a significant bug because it prevents callers from reliably cancelling requests using their own signal. I understand that AbortSignal.any may not yet be widely supported enough for you to want to depend on it directly. Would you be open to an approach that checks for support first, e.g.: If this direction sounds acceptable, I’m happy to update the PR (or open a new one) with tests and any adjustments you’d like to see. Our team does need to address this behavior, and I’d much rather contribute an upstream fix that works for other users than maintain a fork. |
I'll need you to provide a code example that demonstrate this claim, because I don't think that this is true. If you are referring to See the docs: // If you use a custom AbortController associated with the request, pass it in the options object.
wretch("...").addon(AbortAddon()).get().setTimeout(1000, { controller }).json() |
|
You’re right that For example, in Remix v2 loaders you get a export async function loader({ request }: LoaderFunctionArgs) {
return wretch("https://example.com/api")
.addon(AbortAddon())
// must use the framework-provided signal so navigation aborts work
.options({ signal: request.signal })
.get()
.setTimeout(1000) // <- this timeout never aborts the request
.json();
}In this scenario:
Because Remix (and similar environments) don’t expose an |
|
Thanks for the example, it's clearer now. 🙇 Since you are working on an environment where it is fine to rely on "newer" APIs like
// Sounds good to me 👍
if (existingSignal && typeof AbortSignal !== "undefined && "any" in AbortSignal) {
// use AbortSignal.any(existingSignal, addonSignal)
}But in any case, yes adding a guard sounds like a reasonable approach! I just reopened the PR. |
|
Good question — I see where you’re coming from.
Even if I used: const timeoutSignal = AbortSignal.timeout(1000);I’d still need to merge:
into the one signal passed to wretch. That merging is exactly what So |
|
It's worth mentioning that we could solve this for ourselves by creating our own AbortAddon variant internally, but that means other users in similar “signal-only” environments wouldn’t benefit, and our fork would likely drift from upstream over time. That’s why I’m investing in getting this behavior right in the addon itself instead of maintaining a separate copy. |
|
Thanks for the changes, I'll try to review as soon as I have some free time this week.
In addition, I'm sorry to have to write that but please stop feeding everything I write into your AI agent and copy pasting the answer. Its replies are clearly biased and miss up the point half of the time. It is frustrating. |
Fixes a bug where the AbortAddon would ignore user-provided abort signals when users initialize Wretch with a signal or use the .signal() helper method.
Problem
When users provided their own
AbortControllersignal (either via.options({ signal })or .signal(controller)), the AbortAddon would replace it with its own signal instead of respecting both. This meant that:Solution
Modified the beforeRequest hook in the AbortAddon to use
AbortSignal.any()to merge the addon's controller signal with any existing user-provided signal. Now both signals can independently abort the request.Changes:
AbortSignal.any().options({ signal })can abort requests