uppy/packages/@uppy/utils/src
Merlijn Vos 6b1abaa541
@uppy/utils,@uppy/xhr-upload: create and use new queue (#6105)
Closes #4173, kind off

## Problem

Current situation with `RateLimitedQueue`

- Track concurrency: keep a running count, only dispatch up to limit,
accept Infinity.
- Priority enqueue: queued handlers sorted by priority; dequeued in that
order.
- Lifecycle bookkeeping: each job gets abort()/done() hooks; abort for
running vs queued differs; decrement active count and advance queue via
microtasks.
- Requeue placeholders: supports a shouldBeRequeued marker so callers
can hold/retry slots without running immediately.
- Function wrappers: wrap sync or async fns to enforce the queue and
return abortable handles.
- Cancellation plumbing: provides abortOn(signal) to bind queued/running
work to an AbortSignal; abortable promises carry abort().
- Pausing: pause(duration?) freezes dispatch (optional auto-resume);
resume() restarts up to the current limit.
- Rate limiting/backoff: rateLimit(duration) pauses, drops concurrency,
then ramps it back toward the previous upper bound over time.

Case in point: it's some sort of made up, monstrosity data structure
trying to be too many things. It also has rate limiting and exponential
backoff but that's already in
[`fetcher`](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/utils/src/fetcher.ts)
too.

Would be better if we had separation of concerns and proven data
structures.

## Solution

A "dumb" promise-based priority queue that doesn't care at all about
what a promise does or if it needs to be retried. The promise inside
determines if it has retrying and exponential backoff, such as a
`fetcher` promise.

To not make this a breaking change and a huge diff, we still implement
this per uploader, starting with xhr-upload, and keep backwards
compatibility in the interface so we can still pass it to
`companion-client`, which needs to share the same queue.

## Ideal future

When you think about it, it's odd that we implement a queue per uploader
if a queue is so central to uppy working correctly. It's even more odd
that we also have to inject that queue into `companion-client` per
uploader for queue sharing.

Ideally, `core` is responsible for having the queue. All uploaders would
do is push a promise to `core` and `core` doesn't care if that promise
is a tus, xhr, or S3 upload.

---------

Co-authored-by: Prakash <qxprakash@gmail.com>
2026-02-05 15:46:45 +01:00
..
getDroppedFiles Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
AbortController.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
AbortController.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
canvasToBlob.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
CompanionClientProvider.ts Server side search @uppy/Companion (#6003) 2025-10-08 21:18:17 +02:00
CompanionFile.ts @uppy/google-photos: fix various issues (#5275) 2024-06-27 10:31:30 +02:00
dataURItoBlob.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
dataURItoBlob.ts @uppy/utils: improve return type of dataURItoFile (#5112) 2024-04-24 10:48:26 +02:00
dataURItoFile.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
dataURItoFile.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
delay.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
delay.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
emaFilter.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
emaFilter.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
ErrorWithCause.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
ErrorWithCause.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
fetcher.ts fix xhr abort (#6097) 2025-12-09 13:36:02 +07:00
fetchWithNetworkError.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
fileFilters.ts Move completed uploads exclusion logic (#6058) 2025-11-24 19:47:45 +07:00
FileProgress.ts Golden retriever refactor and UppyFile type improvements (#5978) 2025-10-17 23:17:40 +08:00
findAllDOMElements.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
findDOMElement.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
FOCUSABLE_ELEMENTS.ts @uppy/utils: update export maps (#5900) 2025-08-19 12:25:27 +02:00
generateFileID.test.ts @uppy/utils: update export maps (#5900) 2025-08-19 12:25:27 +02:00
generateFileID.ts allow getSafeFileId to accept UppyFile (#6048) 2025-11-03 20:04:57 +08:00
getAllowedMetaFields.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getBytesRemaining.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getBytesRemaining.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getETA.test.ts @uppy/utils: update export maps (#5900) 2025-08-19 12:25:27 +02:00
getETA.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
getFileNameAndExtension.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getFileNameAndExtension.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
getFileType.test.ts Fix type check ci (#5714) 2025-04-09 14:56:38 +02:00
getFileType.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
getFileTypeExtension.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getFileTypeExtension.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
getSocketHost.test.ts @uppy/utils: do not strip www in getSocketHost (#5621) 2025-02-03 15:22:02 +01:00
getSocketHost.ts @uppy/utils: do not strip www in getSocketHost (#5621) 2025-02-03 15:22:02 +01:00
getSpeed.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getSpeed.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
getTextDirection.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
getTimeStamp.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
hasProperty.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
index.ts @uppy/utils,@uppy/xhr-upload: create and use new queue (#6105) 2026-02-05 15:46:45 +01:00
isDOMElement.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
isDragDropSupported.ts chekc for body null (#5959) 2025-09-11 23:14:24 +02:00
isMobileDevice.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
isMobileDevice.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
isNetworkError.test.ts Fix isNetworkError to match MDN spec: readyState === 4 && status === 0 (#6050) 2025-11-05 13:06:21 +08:00
isNetworkError.ts Fix isNetworkError to match MDN spec: readyState === 4 && status === 0 (#6050) 2025-11-05 13:06:21 +08:00
isObjectURL.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
isObjectURL.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
isPreviewSupported.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
isPreviewSupported.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
isTouchDevice.test.ts @uppy/utils: update export maps (#5900) 2025-08-19 12:25:27 +02:00
isTouchDevice.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
microtip.scss meta: run Prettier on existing files (#4713) 2023-09-29 11:11:28 +02:00
mimeTypes.ts @uppy/utils: add msg mimetype (#5699) 2025-04-02 19:08:06 +02:00
NetworkError.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
prettyETA.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
prettyETA.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
ProgressTimeout.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
RateLimitedQueue.test.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
RateLimitedQueue.ts Migrate from Eslint/Prettier/Stylelint to Biome (#5794) 2025-07-01 14:55:41 +02:00
remoteFileObjToLocal.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
sampleImageDataURI.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
secondsToTime.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
secondsToTime.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
TaskQueue.test.ts @uppy/utils,@uppy/xhr-upload: create and use new queue (#6105) 2026-02-05 15:46:45 +01:00
TaskQueue.ts @uppy/utils,@uppy/xhr-upload: create and use new queue (#6105) 2026-02-05 15:46:45 +01:00
toArray.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
toArray.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
Translator.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
Translator.ts lint fix 2025-08-21 14:34:12 +05:30
truncateString.test.ts Use .js(x) for all imports instead .ts(x) (#5573) 2025-01-06 13:29:55 +01:00
truncateString.ts @uppy/utils: refactor to TS (#4699) 2023-11-06 15:01:50 +01:00
UppyFile.ts allow getSafeFileId to accept UppyFile (#6048) 2025-11-03 20:04:57 +08:00
UserFacingApiError.ts @uppy/companion-client: migrate to TS (#4864) 2024-01-24 14:19:38 +01:00
VirtualList.tsx Remove preact/compat (#5935) 2025-08-28 16:57:07 +02:00