will do a separte PR for changes which would require code changes so
it's easier to review , didn't upgrade any deps for `@uppy/aws-s3` since
we'll merge the rewrite so I think we should do that upgrade in the
rewrite branch before merging.
update : Dependency upgrades which required code changes were raised
separately
- #6309
- #6310
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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>
closes#4253
The `isNetworkError` function incorrectly classified XHR states as
network errors. Per MDN, a network error occurs when a request completes
(`readyState === 4`) but has no HTTP status (`status === 0`), indicating
network/CORS/file access failures.
## Changes
- **Logic fix**: Changed from `(xhr.readyState !== 0 && xhr.readyState
!== 4) || xhr.status === 0` to `xhr.readyState === 4 && xhr.status ===
0`
- **Test update**: Removed invalid test expecting `readyState: 2` to be
a network error; added test verifying incomplete requests return `false`
## Example
```typescript
// Before: incorrectly treated in-progress requests as network errors
isNetworkError({ readyState: 2, status: 0 }) // true ❌
// After: only completed requests with no status are network errors
isNetworkError({ readyState: 4, status: 0 }) // true ✓
isNetworkError({ readyState: 2, status: 0 }) // false ✓
```
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
> Update the isNetworkError function in
packages/@uppy/utils/src/isNetworkError.ts to correctly detect network
errors according to MDN documentation. The new logic should return true
only if xhr.readyState === 4 and xhr.status === 0. The updated
implementation should be:
>
> function isNetworkError(xhr?: XMLHttpRequest): boolean {
> if (!xhr) return false
> // finished but status is 0 — usually indicates a network/CORS/file
error
> return xhr.readyState === 4 && xhr.status === 0
> }
>
> export default isNetworkError
>
> No other logic changes are needed. If you find related commentary
(e.g., outdated comments), clarify as needed.
</details>
*This pull request was created as a result of the following prompt from
Copilot chat.*
> Update the isNetworkError function in
packages/@uppy/utils/src/isNetworkError.ts to correctly detect network
errors according to MDN documentation. The new logic should return true
only if xhr.readyState === 4 and xhr.status === 0. The updated
implementation should be:
>
> function isNetworkError(xhr?: XMLHttpRequest): boolean {
> if (!xhr) return false
> // finished but status is 0 — usually indicates a network/CORS/file
error
> return xhr.readyState === 4 && xhr.status === 0
> }
>
> export default isNetworkError
>
> No other logic changes are needed. If you find related commentary
(e.g., outdated comments), clarify as needed.
<!-- START COPILOT CODING AGENT TIPS -->
---
✨ Let Copilot coding agent [set things up for
you](https://github.com/transloadit/uppy/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mifi <402547+mifi@users.noreply.github.com>
fixes#6033
also convert InternalMetadata to interface (interface is preferred when
possible)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Broaden `getSafeFileId` to accept `UppyFile` and extend types by
converting `InternalMetadata` to an interface with optional
`relativePath`.
>
> - **utils**:
> - **`getSafeFileId`**: Broadens parameter via new `SafeFileIdBasis` so
it can accept `UppyFile`; call site logic unchanged.
> - **Types**: Convert `InternalMetadata` to an interface and add
optional `relativePath`; propagate through `UppyFile`/`generateFileID`
typings.
> - **Changeset**: Adds patch entry for `@uppy/utils`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
133240fc0f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
Probably best reviewed commit by commit.
I also split UppyFile into two intefaces distinguished by the `isRemote`
boolean:
- LocalUppyFile
- RemoteUppyFile
Also:
- Removed the TagFile type
- Don't re-upload completed files - fixes#5930
- Clean up stored files on `complete` event *only* if *all* files
succeeded (no failed files). this allows the user to retry failed files
if the browser & upload get interrupted - fixes#5927, closes#5955
- Only set `isGhost` for non-successful files. it doesn't make sense for
successfully uploaded files to be ghosted because they're already done.
#5930fixes#6013
---------
Co-authored-by: Prakash <qxprakash@gmail.com>
## High Level View
<img width="3367" height="1576" alt="Global Search (1)"
src="https://github.com/user-attachments/assets/134e8658-5cbd-4816-87a1-3bd42603089d"
/>
- Search View replicated , through minimal components `<GlobalSearchView
/>` and `<SearchResultItem />`
- Both components take only the minimal state needed to render the
search view no dependency on PartialTree. search response from companion
server is directly passed to GlobalSearchView for file state.
- `#buildPath` creates missing parent nodes in partialTree (if any) and
opens the folder in the normal way using a minimal wrapper over
openFolder function.
- Both interactions : "checking a file/folder" and "opening a folder"
use the same function `#buildPath` to build the path, then use the
already existing `openFolder` and `toggleCheckBox`.
- Max search results: 1000. Pagination removed for simplicity (can be
added later).
- From a UI/UX standpoint, all functionality works as expected.
- The only limitation is occasional inconsistent partial checked states
when the tree isn’t fully built — unavoidable since percolateUp and
percolateDown require the complete partialTree to sync state correctly.
This issue isn’t critical; even in other cases, we already mark folders
"checked" whereas they may be empty if not yet fetched.
- I figured out it's better to just derive the checkedState from
PartialTree , and then pass it to `GlobalSearchView` rather than keep it
separate and then worrying about checked state syncs across two views
for UI to look right.
- IMO this is the most simplest approach I could come up with. without
sacrificing any user functionality and it carefully reuses all the util
code.
---------
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
We drag it in unneccesarily in the bundle and it can cause JSX clashes
in React apps with `"jsx": "preserve"` in their `tsconfig.json`
(https://github.com/preactjs/preact/issues/4908)
- Remove `@types/react` from companion (unused)
- Fix tsconfig's for @uppy/utils (build was fine, but editor diagnostics
weren't)
- cleanup `@uppy/utils ` removed unused / redundant modules .
- migrated modules and tests from `.js` to `.ts`
- removed all the nested export paths
- updated `@uppy/utils` import paths for all packages
- `@uppy/angular` is still failing while running`yarn build` , I'm
looking into it.
---------
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
* Fix type check on CI
it doesn't actually check types in all files
because it used tsconfig.build.json
hence some type errors go unnoticed
* like this
* and this
* add missing references
* fix build command
* stream upload unknown size files
behind a new option streamingUploadSizeless
COMPANION_STREAMING_UPLOAD_SIZELESS
for tus
* allow for all upload protocols
seems to be working
closes#5305
* refactor
and fix bug where progress was not always emitted
* fix type
* fix progress throttling
only do it on total progress
* Improve progress in UI
- only show progress percent and total bytes for files that we know the size of. (but all files will still be included in number of files)
- use `null` as an unknown value for progress and ETA, allowing us to remove ETA from UI when unknown
- `percentage` make use of `undefined` when progress is not yet known - don't show percentage in UI when unknown
- add a new state field `progress` that's the same as `totalProgress` but can also be `null`
* fix build error
* format
* fix progress when upload complete
* use execa for companion load balancer
if not, then it leaves zombie companion instances running in the background when e2e stops
have to be manually killed before running e2e again
* update docs and tests for new state.progress
* revert progress/totalProgress
* improve doc
* remove option streamingUploadSizeless
we agreed that this can be considered not a breaking change
* change progress the to "of unknown"
* revert
* remove companion doc
* add e2e test
* initial poc
* improvements
- split into two plugins
- implement photos picker
- auto login
- save access token in local storage
- document
- handle photos/files picked and send to companion
- add new hook useStore for making it easier to use localStorage data in react
- add new hook useUppyState for making it easier to use uppy state from react
- add new hook useUppyPluginState for making it easier to plugin state from react
- fix css error
* implement picker in companion
* type todo
* fix ts error
which occurs in dev when js has been built before build:ts gets called
* reuse docs
* imrpve type safety
* simplify async wrapper
* improve doc
* fix lint
* fix build error
* check if token is valid
* fix broken logging code
* pull logic out from react component
* remove docs
* improve auth ui
* fix bug
* remove unused useUppyState
* try to fix build error
* FileProgress.ts - convert to typescript
* Buttons.tsx - convert to typescript
Buttons.tsx - convert to typescript (partial)
Buttons.tsx - convert to typescript (partial)
Buttons.tsx - convert to typescript
* everywhere - remove `ComponentChild`
* FileItem.tsx - convert to typescript
* FileList.jsx - fix the comments, they got a bit shuffled some time ago
* FileList.tsx - convert to typscript
* Dashboard.tsx - add back missing props
* FileInfo.tsx - convert to typescript
FileInfo.tsx - convert to typescript (partial)
FileInfo.tsx - convert to typescript
* everywhere - remove excessive props
* ProviderView.tsx - fix onedrive breadcrumbs
* providers - correct ch-unch-indeterminate states
* providers - made .breadcrumbs derived from .partialTree
* everywhere - { files, folders, isChecked } => .partialTree
GoogleDrive
- travelling down into folders works
- checking a file works
- breadcrumbs DONT work
* GoogleDrive - made breadcrumbs work
* .getFolder() - remove the `name` argument
* <Breadcrumbs/> - refactors "/"
* Instagram - made files get fetched onScroll
* clearSelection() - recover the functionality
* GoogleDrive - recover custom `.toggleCheckbox()` functionality
* providers - recover `.isDisabled` functionality
* <SearchProviderView/> - made Unsplash use .partialTree
* Facebook - change `.files, .folders` => `.partialTree`
* everywhere - we don't need to ! `partialTreeFile.data` anymore
* <ProviderView/> - implement folder caching
* <View/> - enable shift-clicking
* everywhere - get rid of unnecessary `.getNextFolder()`
* everywhere - fixing types
* <ProviderView/> - rename `requestPath` to `folderId`
* all providers - get rid of `.onFirstRender()`
* provider views - get rid of `.onFirstRender()`
* <ProviderView/> - make the root folder cacheable too
* TEMP - setup for working with FOLDERS + LAZY_LOADING
* <ProviderView/> - get rid of `.#listFilesAndFolders`
* <ProviderView/> - make `this.nextPagePath` per-folder
* everywhere - more refined types
* types - reintroduce `StatusInPartialTree`
* <SearchProviderView/> - made Unsplash work with the new structure
* <ProviderView/> - preemptive cleaning of `.absDirPath` and `.relDirPath`
* <ProviderView/> - give `.nextPagePath` a rigorous type
* <ProviderView/> - make `.nextPagePath` & `.cached` a composite key
* <ListItem/> - remove unnecessary indirection level
* css - factor out `.statusClassName`
* everywhere - refactor `.validateRestrictions()`
* nOfSelectedFiles - make "Selected (n)" as smart as possible
* <ProviderViews/> - prevent shift-clicking from highlighting file names
* `.validateRestrictions()` - make it accept a `CompanionFile` instead of `PartialTree`'s file
* `.getFolder()` - simplify code
* everywhere - account for `restrictions` in `.partialTree`
* `PartialTreeUtils.ts` - factor out `getPartialTreeAfterTogglingCheckboxes()`
* `PartialTreeUtils.ts` - factor out `clickOnFolder()`
* `PartialTreeUtils.ts` - factor out `getPartialTreeAfterScroll()`
* `PartialTreeUtils.ts` - rename methods
* `.donePicking()` - implement using recursion
* `.donePicking()` - integrate with `<ProviderView/>`
* `donePicking()` - show notifications after addition
* `#list()` - get rid of unnecessary indirection
* ProviderView.tsx - add `signal` everywhere, reduce try/catch indents everywhere
* `handleError()` - make error handling uniform
* `state.isSearchVisible` - remove, it's just not used anywhere
* state - reuse default state
* state - reset state on close panel (like we discussed in the uppy call)
* methods - remove unnecessary indirection in state setting
* `<CloseWrapper/>` - remove CloseWrappers, this is unnecessary indirection now too
* `this.requestClientId` - remove, again - this was unnecessary indirection
* `getTagFile()` - factor out into a separate file
* `recordShiftKeyPress()` - fix chaotic shift-clicking in Grid providers, remove endless prop drilling while we're at it
* `getNOfSelectedFiles.ts`, `filterItems.ts` - factor out, this removes props drilling
* <Browser/> - pass `displayedPartialTree` right away (because Search&NormalProvider have wildly different logics!)
* `searchTerm`, `filterInput` - we only need one of these of course!
* <SearchProvider/> - fix the issue where `afterToggleCheckbox()` thinks we should always filter by `searchString`
* <SearchProvider/> - remove `this.nextPageQuery`
Also: fix the issue where <SearchProvider/> upon searching for "ocean" and then "pajama" would just be adding pajama pictures after the ocean ones
* <Browser/> - remove unnecessary prop indirection
Typescript didn't actually know some of these props aren't used (removed those now)! It only discovers unused props upon normal props passing, like we do now.
* <SearchFilterInput/> - make the form controlled, hugely simplifies everything
* `filterItems.ts` - move to <ProviderView/>, because it's only used there
* /utils/PartialTreeUtils.ts - put every util in a separate file
* `shouldHandleScroll.ts` - factor out into a util
This brings all references to `this.isHandlingScroll` into a single place, and makes `shouldHandleScroll()` a self-contained simple function
* this.state - make sure state is reset 1. on cancel 2. on close
* `this.xxx` - never leave `this.xxx` variables undefined
* `this.username` - should be in `this.state`
Also - when there is no username, stop showing the little dot
* `SearchProviderPluginState` type - simplify this type, never leave state vars undefined
* <Header/> - remove completely unnecessary indirection, remove unused props
* Facebook.tsx - more sane `viewOptions` code
* providers - properly type `opts`
* `this.isShiftKeyPressed` - move this variable into <Browser/>
* `this.handleError()` - move to /utils
* `this.isHandlingScroll` - move to child classes
* `this.registerRequestClient()` - move to child classes
* `this.lastCheckbox` - move to child classes
* `this.setLoading()` - move to child classes
* `this.validateRestrictions()` - move to utils
* types - fully simplify provider types, remove `View.ts` parent class
* index.d.ts - we're not using `OnFirstRenderer` anymore
* <ProviderView/>, <SearchProviderView/> - more precise typing for options
* package.json - remove nanoid
* GoogleDrive - make shift-clicking work
* everywhere - fix types across uppy
* `afterToggleCheckbox.ts` - less redundant args, pass `ourItem.id` instead of `ourItem`
* tests - create `afterToggleCheckbox()` tests
* `getClickedRange.ts` - decouple `getClickedRange()` from `afterToggleCheckbox()`
* tests - wrote tests for `afterToggleCheckbox.ts`
* tests - wrote tests for `afterClickOnFolder.ts`
* everywhere - finally rename `getFolder` => `openFolder`
* tests - wrote tests for `afterScrollFolder.ts`
* getPaths.ts - make `absDirPath`, `relDirPath` work like in docs & add tests for that
* injectPaths.ts - improve performance
* getTagFile.ts - handle path injection all in one place
* getTagFile.ts - refactor
Just makes it easier to read the structure of TagFile
* fill.ts - `provider.list(currentPath, { signal })` => `apiList`
(remove the dependency on provider, just pass a callback)
* tests - wrote tests for `fill.ts`
* tests - wrote tests for `getNOfSelectedFiles.ts`
* everywhere - change `JSON.stringify()` => `clone()`
* `PartialTreeUtils.ts` - more consistent function naming + alphabetical order in tests
* `donePicking()` - superseded a notification to i18n one
* GoogleDrive - make the shared drive checkable
* `Item.tsx` - standardize names; remove unnecessary question marks from props
* ProviderView.tsx - clicking "Cancel" should make all files "unchecked"
* everywhere - move `document.getSelection()?.removeAllRanges()` to <Browser/> to avoid repetition
* everywhere - standardize names and types of passed props
* <Browser/> - only leave "list of files" to the browser
Moves stuff closer to where it's used, prevents props drilling
* TEMP - easier pageSize for alex to play with
When it's set to 5 pages you have to reduce the browser window to make it scrollable
* everywhere - only handle individual-file restrictions
* everywhere - add aggregate restrictions on top
* SearchProvider, NormalProvider - unite the way we addFiles()
Same notifications, same code, same everything
* `getTagFile.ts` - pass fewer arguments
* `addFiles.ts` - move conversion to tagFiles into `addFiles()`
* `uppy.validateRestrictions()` - remove legacy method
* `uppy.validateAggregateRestrictions()` - make aggregate restricter report aggregate error
* <FooterActions/> css - make aggregate errors look nice
* `PartialTreeUtils/index.test.ts` - accommodate tests to the latest changes
* tests - make all uppy tests work
* prettiness - run `yarn format`
* prettiness - run `yarn lint:fix`
* package.json - add `vitest` as a dev dependency
* eslint - fixing 1
eslint - fixing 2
eslint - fixing 3
* <SearchFilterInput/> - add default props as per eslint
* <SearchFilterInput/> - rename to <SearchInput/>
* eslint - fixing 4 (clone.ts)
* Uppy.ts - rewrite `partialTree` docs
* eslint - fixing 5
* eslint - fixing 6
* `getBreadcrumbs.ts` - factor out
* tests - fixing 7
* everywhere - remove `.toReversed()`, because it's not yet supported in all browsers
* dev/Dashboard.js - restore to pristine version
* prettiness - run `yarn format`
* fixing 8 (`yarn run build:ts`)
* fixing 9 (run `corepack yarn`)
* prettier - undo indentation harm done by prettier
* `getBreadcrumbs()` - add tests, and rewrite to avoid using `.toReversed()`
Clarification: `.toReversed()` is no supported by all browsers
* `<SearchInput/>` - make it work for eslint
* everywhere - remove `eslint-disable react/require-default-props`
* <GridItem/>, <ListItem/> - refactor to avoid prop drilling
* <ListItem/> - disable checkboxes for GoogleDrive team drives
See #5232
* merge (fixing up some lines from the previous merge)
* merge (fixing up some lines from the previous merge)
* everywhere - remove TEMP development values
* `this.validateSingleFile()` - switch to `.restrictionError`
* `afterToggleCheckbox.ts` - refactor, add comments
* `afterToggleCheckbox.ts` - refactor to use ids instead of whole objects
* `afterToggleCheckbox.ts` - try to satisfy prettier
* fixing 10 (try to satisfy `npx webpack`)
* fixing 11 (try to satisfy `npx webpack`)
* Antoine: use Math.min & Math.max in `getClickedRange()`
Co-authored-by: Antoine du Hamel <antoine@transloadit.com>
* fixing 12 (run `yarn run format`)
* `clone.ts` - rename to `shallowClone.ts`
* Antoine: in `package.json`, move `devDependencies` up
* Antoine: rename `getNOfSelectedFiles()` to `getNumberOfSelectedFiles()`
* `getNumberOfSelectedFiles()` - better comments
* Antoine: remove `<form/>` tag
* Antoine: change `{}` to `Object.create(null)`, write tests
* Antoine: `<SearchInput/>` - return dynamic <form/> element
* `<SearchInput/>` - return `buttonCSSClassName`
* `GoogleDrive.tsx` - make team drive checkboxes visible
* merge (more)
* Mifi: update packages/@uppy/provider-views/src/ProviderView/ProviderView.tsx
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
* merge (more changes)
* `Facebook.tsx`, `GooglePhotos.tsx` - render in 'grid' style on per-folder basis
* `<GridItem/>` - use the `.thumbnail` whenever possible (improves image quality, adds video icons)
* `prettier` - ensure `PartialTree` is always strongly indented in tests
---------
Co-authored-by: Antoine du Hamel <antoine@transloadit.com>
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
* main:
meta: enable prettier for markdown (#5133)
@uppy/xhr-upload: do not throw when res is missing url (#5132)
@uppy/companion: coerce `requestUrl` to a string (#5128)
Release: uppy@3.25.0 (#5127)
meta: enforce use of `.js` extension in `import type` declarations (#5126)
@uppy/core: add instance ID to generated IDs (#5080)
@uppy/core: reference updated i18n in Restricter (#5118)
* main: (22 commits)
@uppy/xhr-upload: refactor to use `fetcher` (#5074)
docs: use StackBlitz for all examples/issue template (#5125)
Update yarn.lock
Add svelte 5 as peer dep (#5122)
Bump docker/setup-buildx-action from 2 to 3 (#5124)
Bump actions/checkout from 3 to 4 (#5123)
Remove JSX global type everywhere (#5117)
Revert "@uppy/core: reference updated i18n in Restricter"
@uppy/core: reference updated i18n in Restricter
@uppy/utils: improve return type of `dataURItoFile` (#5112)
@uppy/drop-target: change drop event type to DragEvent (#5107)
@uppy/image-editor: fix label definitions (#5111)
meta: bump Prettier version (#5114)
@uppy/provider-views: bring back "loaded X files..." (#5097)
@uppy/dashboard: fix type of trigger option (#5106)
meta: fix linter
@uppy/form: fix `submitOnSuccess` and `triggerUploadOnSubmit` combination (#5058)
Bump docker/build-push-action from 3 to 5 (#5105)
Bump akhileshns/heroku-deploy from 3.12.12 to 3.13.15 (#5102)
Bump docker/login-action from 2 to 3 (#5101)
...