diff --git a/.changeset/bright-tables-kiss.md b/.changeset/bright-tables-kiss.md deleted file mode 100644 index 1f708416b..000000000 --- a/.changeset/bright-tables-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@uppy/locales": patch ---- - -Update cs_CZ dropPaste keys to use the correct variables. diff --git a/.changeset/clean-monkeys-smoke.md b/.changeset/clean-monkeys-smoke.md deleted file mode 100644 index f51d946e5..000000000 --- a/.changeset/clean-monkeys-smoke.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@uppy/components": patch -"@uppy/vue": patch ---- - -- Fix Vue components to work with kebab-case props (`:edit-file` instead of `:editFile`) diff --git a/.changeset/curvy-feet-chew.md b/.changeset/curvy-feet-chew.md new file mode 100644 index 000000000..4cfe7f172 --- /dev/null +++ b/.changeset/curvy-feet-chew.md @@ -0,0 +1,45 @@ +--- +"@uppy/angular": patch +"@uppy/google-photos-picker": patch +"@uppy/google-drive-picker": patch +"@uppy/thumbnail-generator": patch +"@uppy/companion-client": patch +"@uppy/golden-retriever": patch +"@uppy/image-generator": patch +"@uppy/provider-views": patch +"@uppy/remote-sources": patch +"@uppy/screen-capture": patch +"@uppy/store-default": patch +"@uppy/google-drive": patch +"@uppy/image-editor": patch +"@uppy/transloadit": patch +"@uppy/components": patch +"@uppy/compressor": patch +"@uppy/status-bar": patch +"@uppy/xhr-upload": patch +"@uppy/companion": patch +"@uppy/dashboard": patch +"@uppy/drag-drop": patch +"@uppy/facebook": patch +"@uppy/onedrive": patch +"@uppy/unsplash": patch +"@uppy/dropbox": patch +"@uppy/locales": patch +"@uppy/aws-s3": patch +"@uppy/svelte": patch +"@uppy/webcam": patch +"@uppy/webdav": patch +"@uppy/audio": patch +"@uppy/react": patch +"@uppy/utils": patch +"@uppy/core": patch +"@uppy/form": patch +"@uppy/zoom": patch +"@uppy/box": patch +"@uppy/tus": patch +"@uppy/url": patch +"@uppy/vue": patch +"uppy": patch +--- + +Bump shared runtime dependencies (preact, nanoid, lodash, classnames, shallow-equal, pretty-bytes, p-queue, tus-js-client, @transloadit/types @transloadit/prettier-bytes v1, is-mobile, exifr, compressorjs, rxjs, tslib). Also includes type-only fixes in `@uppy/companion`'s `jwt.ts` and `request.ts` to track `@types/jsonwebtoken` v9 and `@types/node`. \ No newline at end of file diff --git a/.changeset/dry-readers-itch.md b/.changeset/dry-readers-itch.md deleted file mode 100644 index 69b5600fe..000000000 --- a/.changeset/dry-readers-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@uppy/tus": patch ---- - -Fix Node.js support by conditionally setting a property which does not exist in Node.js instead of crashing. diff --git a/.changeset/few-plants-pump.md b/.changeset/few-plants-pump.md new file mode 100644 index 000000000..a094e2988 --- /dev/null +++ b/.changeset/few-plants-pump.md @@ -0,0 +1,5 @@ +--- +"@uppy/dashboard": patch +--- + +fix "My Device" button in dashboard, it now respects the fileManagerSelectionType. diff --git a/.changeset/giant-berries-warn.md b/.changeset/giant-berries-warn.md deleted file mode 100644 index 35365bc1c..000000000 --- a/.changeset/giant-berries-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@uppy/transloadit": minor ---- - -Migrate from 'transloadit' to '@transloadit/types' to get the types. No need to drag in the entire SDK. diff --git a/.changeset/gold-rice-jog.md b/.changeset/gold-rice-jog.md new file mode 100644 index 000000000..71b7a8fc0 --- /dev/null +++ b/.changeset/gold-rice-jog.md @@ -0,0 +1,9 @@ +--- +"@uppy/components": major +"@uppy/companion": major +"uppy": major +"@uppy/transloadit": minor +"@uppy/locales": minor +--- + +Remove @uppy/instagram references from all the packages diff --git a/.changeset/happy-timers-kick.md b/.changeset/happy-timers-kick.md new file mode 100644 index 000000000..d06fc6eb1 --- /dev/null +++ b/.changeset/happy-timers-kick.md @@ -0,0 +1,5 @@ +--- +"@uppy/aws-s3": patch +--- + +Improve type diff --git a/.changeset/lazy-berries-brake.md b/.changeset/lazy-berries-brake.md new file mode 100644 index 000000000..5aa8c52c5 --- /dev/null +++ b/.changeset/lazy-berries-brake.md @@ -0,0 +1,5 @@ +--- +"@uppy/companion-client": patch +--- + +uploadRemoteFile() now queues token request and websocket request as a single job in the request queue. diff --git a/.changeset/legal-drinks-marry.md b/.changeset/legal-drinks-marry.md new file mode 100644 index 000000000..e859660be --- /dev/null +++ b/.changeset/legal-drinks-marry.md @@ -0,0 +1,5 @@ +--- +"@uppy/transloadit": minor +--- + +Add assemblyStatus and lastAssemblyStatus to transloadit's plugin state diff --git a/.changeset/mighty-deers-sin.md b/.changeset/mighty-deers-sin.md new file mode 100644 index 000000000..71159166a --- /dev/null +++ b/.changeset/mighty-deers-sin.md @@ -0,0 +1,8 @@ +--- +"@uppy/companion-client": major +"@uppy/companion": major +--- + +Send token using websocket instead of window.opener. +Breaking in `@uppy/companion-client` because it needs newest version of Companion in order to work. +Breaking in `@uppy/companion` because `companion.socket()` now requires `companionOptions` to be passed as the second argument. diff --git a/.changeset/proud-spies-train.md b/.changeset/proud-spies-train.md new file mode 100644 index 000000000..10d332013 --- /dev/null +++ b/.changeset/proud-spies-train.md @@ -0,0 +1,5 @@ +--- +"@uppy/transloadit": patch +--- + +emit updated AssemblyState in 'transloadit:assembly-cancelled' event diff --git a/.changeset/smooth-chefs-occur.md b/.changeset/smooth-chefs-occur.md new file mode 100644 index 000000000..66a598445 --- /dev/null +++ b/.changeset/smooth-chefs-occur.md @@ -0,0 +1,5 @@ +--- +"@uppy/companion": major +--- + +Upgrade to express 5 - Companion no longer works when used as a middleware with Express 4. diff --git a/.changeset/three-cobras-lick.md b/.changeset/three-cobras-lick.md new file mode 100644 index 000000000..e601129d4 --- /dev/null +++ b/.changeset/three-cobras-lick.md @@ -0,0 +1,5 @@ +--- +"@uppy/companion": patch +--- + +Port Companion to TypeScript. Not really a breaking change but there could be some unexpected breakage. diff --git a/.env.example b/.env.example index a3bbe74b7..f8ccdd5f4 100644 --- a/.env.example +++ b/.env.example @@ -44,9 +44,6 @@ COMPANION_DROPBOX_SECRET=*** COMPANION_GOOGLE_KEY=*** COMPANION_GOOGLE_SECRET=*** -COMPANION_INSTAGRAM_KEY=*** -COMPANION_INSTAGRAM_SECRET=*** - COMPANION_FACEBOOK_KEY=*** COMPANION_FACEBOOK_SECRET=*** diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 22ea1f915..b154e0281 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -57,7 +57,7 @@ This is not needed for changing existing components. ## Companion If you’d like to work on features that the basic development version of Uppy -doesn’t support, such as Uppy integrations with Instagram/Google Drive/Facebook +doesn’t support, such as Uppy integrations with Google Drive/Facebook etc., you need to set up your `.env` file (copy the contents of `.env.example` and adjust them based on what you need to work on), and run: @@ -78,7 +78,7 @@ when files are changed. ### How the Authentication and Token mechanism works This section describes how Authentication works between Companion and Providers. -While this behaviour is the same for all Providers (Dropbox, Instagram, Google +While this behaviour is the same for all Providers (Dropbox, Google Drive, etc.), we are going to be referring to Dropbox in place of any Provider throughout this section. diff --git a/.github/workflows/bundlers.yml b/.github/workflows/bundlers.yml index 0f2035da8..a0dcf03ee 100644 --- a/.github/workflows/bundlers.yml +++ b/.github/workflows/bundlers.yml @@ -42,7 +42,7 @@ jobs: node-version: lts/* - name: Install dependencies run: - corepack yarn install + corepack yarn install --immutable env: # https://docs.cypress.io/guides/references/advanced-installation#Skipping-installation CYPRESS_INSTALL_BINARY: 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d657c7ef..8846111ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: node-version: ${{matrix.node-version}} - name: Install dependencies run: - corepack yarn install + corepack yarn install --immutable - name: Install Playwright Browsers run: corepack yarn workspace @uppy/dashboard playwright install --with-deps - name: Build @@ -84,7 +84,7 @@ jobs: node-version: lts/* - name: Install dependencies run: - corepack yarn install + corepack yarn install --immutable - run: corepack yarn run typecheck lint_js: diff --git a/.github/workflows/companion-deploy.yml b/.github/workflows/companion-deploy.yml index 40fab2d0f..c1de42d81 100644 --- a/.github/workflows/companion-deploy.yml +++ b/.github/workflows/companion-deploy.yml @@ -38,56 +38,49 @@ jobs: path: /tmp/companion-${{ github.sha }}.tar.gz docker: - name: DockerHub - runs-on: ubuntu-latest - env: - DOCKER_BUILDKIT: 0 - COMPOSE_DOCKER_CLI_BUILD: 0 + name: DockerHub (${{ matrix.platform }}) + strategy: + matrix: + include: + - runner: ubuntu-24.04 + platform: linux/amd64 + platform_tag: amd64 + - runner: ubuntu-24.04-arm + platform: linux/arm64 + platform_tag: arm64 + runs-on: ${{ matrix.runner }} steps: - name: Checkout sources uses: actions/checkout@v6 - - name: Docker meta - id: docker_meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 - with: - images: transloadit/companion - tags: | - type=edge - type=raw,value=latest,enable=false - - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - name: Log in to DockerHub - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: - username: ${{secrets.DOCKER_USERNAME}} - password: ${{secrets.DOCKER_PASSWORD}} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: push: true context: . - platforms: linux/amd64,linux/arm64 + platforms: ${{ matrix.platform }} file: Dockerfile - tags: ${{ steps.docker_meta.outputs.tags }} - labels: ${{ steps.docker_meta.outputs.labels }} + tags: transloadit/companion:edge-${{ matrix.platform_tag }} - heroku: - name: Heroku + docker-manifest: + name: DockerHub manifest + needs: docker runs-on: ubuntu-latest steps: - - name: Checkout sources - uses: actions/checkout@v6 - - name: Alter dockerfile - run: | - sed -i 's/^EXPOSE 3020$/EXPOSE $PORT/g' Dockerfile - # https://github.com/AkhileshNS/heroku-deploy/issues/188 - - name: Install Heroku CLI - run: | - curl https://cli-assets.heroku.com/install.sh | sh - - name: Deploy to heroku - uses: akhileshns/heroku-deploy@e3eb99d45a8e2ec5dca08735e089607befa4bf28 # v3.14.15 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f + - name: Log in to DockerHub + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: - heroku_api_key: ${{secrets.HEROKU_API_KEY}} - heroku_app_name: companion-demo - heroku_email: ${{secrets.HEROKU_EMAIL}} - usedocker: true + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Publish edge manifest + run: | + docker buildx imagetools create \ + --tag transloadit/companion:edge \ + transloadit/companion:edge-amd64 \ + transloadit/companion:edge-arm64 diff --git a/.github/workflows/manual-cdn.yml b/.github/workflows/manual-cdn.yml index 2d511a965..0efbe6fa7 100644 --- a/.github/workflows/manual-cdn.yml +++ b/.github/workflows/manual-cdn.yml @@ -30,18 +30,6 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v6 - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: - echo "dir=$(corepack yarn config get cacheFolder)" >> $GITHUB_OUTPUT - - - uses: actions/cache@v5 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: Install Node.js uses: actions/setup-node@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6e8db1211..58284cdc7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,11 @@ on: branches: - main +permissions: + id-token: write # Required for OIDC + contents: write + pull-requests: write + concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: @@ -28,6 +33,7 @@ jobs: uses: actions/setup-node@v6 with: node-version: lts/* + registry-url: "https://registry.npmjs.org" # Allow yarn to make changes during release - run: corepack yarn config set enableHardenedMode false @@ -39,28 +45,19 @@ jobs: - name: Build run: corepack yarn build - - name: '@uppy/angular prepublish' + - name: "@uppy/angular prepublish" run: corepack yarn workspace @uppy/angular prepublishOnly - - run: | - echo '' >> .yarnrc.yml - echo 'npmAuthToken: "${NPM_TOKEN}"' >> .yarnrc.yml - - name: Create Release Pull Request or Publish id: changesets - uses: changesets/action@v1 + uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d with: version: corepack yarn run version publish: corepack yarn run release - commit: '[ci] release' - title: '[ci] release' + commit: "[ci] release" + title: "[ci] release" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Remove npmAuthToken from yarnrc - run: | - sed -i '/npmAuthToken:/d' .yarnrc.yml - name: Check if Companion was released id: checkIfCompanionWasReleased @@ -82,7 +79,6 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - # See also companion-deploy.yml docker: name: DockerHub @@ -106,14 +102,14 @@ jobs: # set latest tag for default branch type=raw,value=latest,enable=true - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - name: Log in to DockerHub - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{secrets.DOCKER_USERNAME}} password: ${{secrets.DOCKER_PASSWORD}} - name: Build and push - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: push: true context: . diff --git a/.yarnrc.yml b/.yarnrc.yml index d2890fb76..2057decd7 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -9,5 +9,6 @@ initScope: uppy nodeLinker: node-modules -npmPublishAccess: public +npmMinimalAgeGate: 2880 +npmPublishAccess: public diff --git a/BUNDLE-README.md b/BUNDLE-README.md index 63d0d8a40..5e6396bd5 100644 --- a/BUNDLE-README.md +++ b/BUNDLE-README.md @@ -2,7 +2,7 @@ Hi, thanks for trying out the bundled version of the Uppy File Uploader. You can use this from a CDN -(``) +(``) or bundle it with your webapp. Note that the recommended way to use Uppy is to install it with yarn/npm and use @@ -83,7 +83,7 @@ inline into the page. This, and many more configuration options can be found here: . Uppy has many more Plugins besides Xhr and the Dashboard. For example, you can -enable Webcam, Instagram, or video encoding support. Note that for some Plugins, +enable Webcam or video encoding support. Note that for some Plugins, you will need to run a server side component called: Companion. Those plugins are marked with a (c) symbol. Alternatively, you can sign up for a free Transloadit account. Transloadit runs Companion for you, tusd servers to handle diff --git a/CLAUDE.md b/CLAUDE.md index eb73dda14..4091038aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -46,7 +46,7 @@ yarn workspace @uppy/[package-name] build - **Uppy Core** (`@uppy/core`) - Main class that manages plugins, state, and events - **Plugins** - Modular components for different functionalities: - **UI Plugins**: Dashboard, Drag & Drop, File Input, Webcam, etc. - - **Provider Plugins**: Google Drive, Dropbox, Instagram, etc. (require Companion) + - **Provider Plugins**: Google Drive, Dropbox, etc. (require Companion) - **Uploader Plugins**: Tus (resumable), XHR Upload, AWS S3, etc. - **Utility Plugins**: Golden Retriever (recovery), Thumbnail Generator, etc. diff --git a/Dockerfile b/Dockerfile index 5ce604c25..3d7cbc3ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,13 +22,12 @@ FROM node:22.18.0-alpine WORKDIR /app # copy required files from build stage. -COPY --from=build /app/packages/@uppy/companion/bin /app/bin -COPY --from=build /app/packages/@uppy/companion/lib /app/lib +COPY --from=build /app/packages/@uppy/companion/dist /app/dist COPY --from=build /app/packages/@uppy/companion/package.json /app/package.json COPY --from=build /app/packages/@uppy/companion/node_modules /app/node_modules ENV PATH "${PATH}:/app/node_modules/.bin" -CMD ["node","/app/bin/companion"] +CMD ["node","/app/dist/bin/companion.js"] # This can be overruled later EXPOSE 3020 diff --git a/README.md b/README.md index 5fbb450b9..2b63aff7f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ with any application. It’s fast, has a comprehensible API and lets you worry about more important problems than building a file uploader. - **Fetch** files from local disk, remote URLs, Google Drive, Dropbox, Box, - Instagram or snap and record selfies with a camera + or snap and record selfies with a camera - **Preview** and edit metadata with a nice interface - **Upload** to the final destination, optionally process/encode @@ -82,7 +82,7 @@ For the supported frameworks (except Angular) Uppy offers three ways to build us - Lightweight, modular plugin-based architecture, light on dependencies :zap: - Resumable file uploads via the open [tus](https://tus.io/) standard, so large uploads survive network hiccups -- Supports picking files from: Webcam, Dropbox, Box, Google Drive, Instagram, +- Supports picking files from: Webcam, Dropbox, Box, Google Drive, bypassing the user’s device where possible, syncing between servers directly via [@uppy/companion](https://uppy.io/docs/companion) - Works great with file encoding and processing backends, such as @@ -103,7 +103,7 @@ npm install @uppy/core @uppy/dashboard @uppy/tus ``` Add CSS -[uppy.min.css](https://releases.transloadit.com/uppy/v5.2.2/uppy.min.css), +[uppy.min.css](https://releases.transloadit.com/uppy/v5.2.4/uppy.min.css), either to your HTML page’s `` or include in JS, if your bundler of choice supports it. @@ -117,7 +117,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object. ```html @@ -128,7 +128,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object. Uppy, Dashboard, Tus, - } from 'https://releases.transloadit.com/uppy/v5.2.2/uppy.min.mjs' + } from 'https://releases.transloadit.com/uppy/v5.2.4/uppy.min.mjs' const uppy = new Uppy() uppy.use(Dashboard, { target: '#files-drag-drop' }) @@ -140,7 +140,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object. - [Uppy](https://uppy.io/docs/uppy/) — full list of options, methods and events - [Companion](https://uppy.io/docs/companion/) — setting up and running a - Companion instance, which adds support for Instagram, Dropbox, Box, Google + Companion instance, which adds support for Dropbox, Box, Google Drive and remote URLs - [React](https://uppy.io/docs/react/) — components to integrate Uppy UI plugins with React apps @@ -153,7 +153,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object. - [`Dashboard`](https://uppy.io/docs/dashboard/) — universal UI with previews, progress bars, metadata editor and all the cool stuff. Required for most UI - plugins like Webcam and Instagram + plugins like Webcam - Headless components ([react](https://uppy.io/docs/react/), [svelte](https://uppy.io/docs/svelte/), [vue](https://uppy.io/docs/vue/)) ### Sources @@ -166,8 +166,6 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object. Google Drive - ⓒ [`Dropbox`](https://uppy.io/docs/dropbox/) — import files from Dropbox - ⓒ [`Box`](https://uppy.io/docs/box/) — import files from Box -- ⓒ [`Instagram`](https://uppy.io/docs/instagram/) — import images and videos - from Instagram - ⓒ [`Facebook`](https://uppy.io/docs/facebook/) — import images and videos from Facebook - ⓒ [`OneDrive`](https://uppy.io/docs/onedrive/) — import files from Microsoft @@ -222,7 +220,7 @@ cases, the file input leaves some to be desired: - Uppy supports editing meta information before uploading. - Uppy allows cropping images before uploading. - There’s the situation where people are using their mobile devices and want to - upload on the go, but they have their picture on Instagram, files in Dropbox + upload on the go, but they have files in Dropbox or a plain file URL from anywhere on the open web. Uppy allows to pick files from those and push it to the destination without downloading it to your mobile device first. @@ -272,7 +270,7 @@ If you want resumability with the Tus plugin, use [one of the tus server implementations](https://tus.io/implementations.html) 👌🏼 And you’ll need [`@uppy/companion`](https://uppy.io/docs/companion) if you’d -like your users to be able to pick files from Instagram, Google Drive, Dropbox +like your users to be able to pick files from Google Drive, Dropbox or via direct URLs (with more services coming). ## Contributions are welcome diff --git a/biome.json b/biome.json index 5ccb0bae6..13f580c8c 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json", "vcs": { "enabled": true, "clientKind": "git", @@ -14,10 +14,11 @@ "bin/**", "e2e/**", "private/**", - "!packages/**/{dist,lib}/**", + "!packages/**/{dist,lib}", "!node_modules", "!.svelte-kit", - "!packages/@uppy/components/src/input.css" + "!packages/@uppy/components/src/input.css", + "!examples/angular/**/*.html" ] }, "formatter": { @@ -25,20 +26,11 @@ "indentStyle": "space", "formatWithErrors": true }, + "html": { + "experimentalFullSupportEnabled": true + }, "linter": { "enabled": true, - "includes": [ - "packages/**", - "examples/**", - "scripts/**", - "private/**", - "!packages/**/{dist,lib}/**", - "!node_modules", - "!.svelte-kit", - "!packages/@uppy/components/src/input.css", - "!**/*.vue", - "!**/*.svelte" - ], "rules": { "recommended": true, "suspicious": { @@ -48,22 +40,23 @@ "useExhaustiveDependencies": "error", "useHookAtTopLevel": "error", "noUnusedFunctionParameters": "off", + "noUnusedImports": "error", + "noUnusedPrivateClassMembers": "error", "noUnusedVariables": { "level": "error", "options": { "ignoreRestSiblings": true } - } + }, + "noNestedComponentDefinitions": "error", + "noReactPropAssignments": "error" }, "style": { "noNonNullAssertion": "off" }, "a11y": { - "noSvgWithoutTitle": "off" - }, - "nursery": { - "noNestedComponentDefinitions": "error", - "noReactPropAssign": "error" + "noSvgWithoutTitle": "off", + "useSemanticElements": "off" } } }, @@ -80,5 +73,36 @@ "organizeImports": "on" } } - } + }, + "overrides": [ + { + "includes": ["packages/@uppy/companion/**"], + "linter": { + "rules": { + "complexity": { + "useLiteralKeys": "off" + } + } + } + }, + { + "includes": ["**/*.vue", "**/*.svelte", "packages/@uppy/vue/**/*.ts"], + "linter": { + "rules": { + "correctness": { + "useHookAtTopLevel": "off", + "useExhaustiveDependencies": "off" + } + } + } + }, + { + "includes": ["examples/nextjs/**/*.css"], + "css": { + "parser": { + "tailwindDirectives": true + } + } + } + ] } diff --git a/examples/aws-companion/index.html b/examples/aws-companion/index.html index 0b86787b7..01eacb7a8 100644 --- a/examples/aws-companion/index.html +++ b/examples/aws-companion/index.html @@ -1,5 +1,5 @@ - + diff --git a/examples/aws-companion/main.js b/examples/aws-companion/main.js index 29cbaea58..7c1dd7f43 100644 --- a/examples/aws-companion/main.js +++ b/examples/aws-companion/main.js @@ -23,5 +23,5 @@ uppy.use(Dashboard, { plugins: ['GoogleDrive', 'Webcam'], }) uppy.use(AwsS3, { - companionUrl: 'http://localhost:3020', + endpoint: 'http://localhost:3020', }) diff --git a/examples/aws-companion/package.json b/examples/aws-companion/package.json index f061bbcdb..9c02f8a2c 100644 --- a/examples/aws-companion/package.json +++ b/examples/aws-companion/package.json @@ -11,11 +11,11 @@ }, "devDependencies": { "@uppy/companion": "workspace:*", - "body-parser": "^1.20.4", + "body-parser": "^2.2.2", "cookie-parser": "^1.4.7", "cors": "^2.8.5", - "dotenv": "^16.0.1", - "express": "^4.22.0", + "dotenv": "^17.4.2", + "express": "^5.2.1", "express-session": "^1.17.3", "npm-run-all": "^4.1.5", "vite": "^7.1.11" diff --git a/examples/aws-companion/server.cjs b/examples/aws-companion/server.cjs index 010d7e644..bcbc1e025 100644 --- a/examples/aws-companion/server.cjs +++ b/examples/aws-companion/server.cjs @@ -10,7 +10,7 @@ const DATA_DIR = path.join(__dirname, 'tmp') app.use( require('cors')({ - origin: 'http://localhost:3000', + origin: 'http://localhost:5173', methods: ['GET', 'POST', 'OPTIONS'], credentials: true, }), @@ -45,6 +45,7 @@ const options = { filePath: DATA_DIR, secret: 'blah blah', debug: true, + corsOrigins: true, } // Create the data directory here for the sake of the example. @@ -65,4 +66,4 @@ const server = app.listen(3020, () => { console.log('listening on port 3020') }) -companion.socket(server) +companion.socket(server, options) diff --git a/examples/aws-nodejs/package.json b/examples/aws-nodejs/package.json index cfcbde2a1..bdc013ed0 100644 --- a/examples/aws-nodejs/package.json +++ b/examples/aws-nodejs/package.json @@ -15,6 +15,6 @@ "@aws-sdk/s3-request-presigner": "^3.338.0", "body-parser": "^1.20.4", "dotenv": "^16.0.0", - "express": "^4.22.0" + "express": "^5.2.1" } } diff --git a/examples/aws-nodejs/public/index.html b/examples/aws-nodejs/public/index.html index 881a07567..cd7d79f60 100644 --- a/examples/aws-nodejs/public/index.html +++ b/examples/aws-nodejs/public/index.html @@ -1,5 +1,5 @@ - + Uppy – AWS upload example @@ -24,7 +24,8 @@ + +
+
+

Edit Image

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + + + + +
+ +
+ + + + +
+ +
+ + +
+
diff --git a/examples/sveltekit/src/components/MediaCapture.svelte b/examples/sveltekit/src/components/MediaCapture.svelte index cb68b6391..148043e58 100644 --- a/examples/sveltekit/src/components/MediaCapture.svelte +++ b/examples/sveltekit/src/components/MediaCapture.svelte @@ -42,36 +42,37 @@ const {

{mediaError.message ? `Camera error: ${mediaError.message}` : 'An unknown camera error occurred.'}

{/if} +
- - - - - + - +
diff --git a/examples/sveltekit/src/routes/+page.svelte b/examples/sveltekit/src/routes/+page.svelte index a134ca9ed..c9832a059 100644 --- a/examples/sveltekit/src/routes/+page.svelte +++ b/examples/sveltekit/src/routes/+page.svelte @@ -1,5 +1,6 @@ @@ -59,18 +75,21 @@ function closeModal() { {#if modalPlugin === 'screen-capture'} {/if} + {#if modalPlugin === 'image-editor' && selectedFile} + + {/if}

With list

- +

With grid

- +
diff --git a/examples/sveltekit/test/index.test.ts b/examples/sveltekit/test/index.test.ts index 3c33fd04b..b2c019428 100644 --- a/examples/sveltekit/test/index.test.ts +++ b/examples/sveltekit/test/index.test.ts @@ -1,16 +1,26 @@ -import { userEvent } from '@vitest/browser/context' -import { describe, expect, test } from 'vitest' +import { setupWorker } from 'msw/browser' +import { afterAll, beforeAll, describe, expect, test } from 'vitest' +import { userEvent } from 'vitest/browser' import { render } from 'vitest-browser-svelte' +import { tusHandlers } from '../../shared/tusHandlers.js' import PropsReactivity from '../src/components/test/props-reactivity.svelte' import App from '../src/routes/+page.svelte' +const worker = setupWorker(...tusHandlers) +beforeAll(async () => { + await worker.start({ onUnhandledRequest: 'error' }) +}) +afterAll(() => { + worker.stop() +}) + const createMockFile = (name: string, type: string, size: number = 1024) => { return new File(['test content'], name, { type }) } describe('App', () => { test('renders all main sections and upload button is initially disabled', async () => { - const screen = render(App) + const screen = await render(App) await expect.element(screen.getByText('With list')).toBeInTheDocument() await expect.element(screen.getByText('With grid')).toBeInTheDocument() @@ -24,7 +34,7 @@ describe('App', () => { }) test('can add and remove files and upload', async () => { - const screen = render(App) + const screen = await render(App) const fileInput = document.getElementById( 'uppy-dropzone-file-input-uppy', @@ -50,7 +60,7 @@ describe('App', () => { describe('ScreenCapture Component', () => { test('renders with title, control buttons, and close functionality works', async () => { - const screen = render(App) + const screen = await render(App) await screen .getByRole('button', { name: 'Screen Capture', exact: true }) @@ -83,7 +93,7 @@ describe('ScreenCapture Component', () => { describe('Webcam Component', () => { test('renders with title, control buttons, and close functionality works', async () => { - const screen = render(App) + const screen = await render(App) await screen.getByRole('button', { name: 'Webcam', exact: true }).click() @@ -114,7 +124,7 @@ describe('Webcam Component', () => { describe('RemoteSource Component', () => { test('renders login button and login interaction works', async () => { - const screen = render(App) + const screen = await render(App) await screen.getByRole('button', { name: 'Dropbox', exact: true }).click() @@ -122,12 +132,11 @@ describe('RemoteSource Component', () => { await expect.element(loginButton).toBeInTheDocument() await loginButton.click() - await expect.element(loginButton).toBeInTheDocument() }) }) test('Dashboard reacts to prop changes', async () => { - const screen = render(PropsReactivity) + const screen = await render(PropsReactivity) const toggleButton = screen.getByText('Toggle dashboard') const dashboard = screen.container.querySelector('.uppy-Dashboard') @@ -138,7 +147,7 @@ test('Dashboard reacts to prop changes', async () => { }) test('StatusBar reacts to prop changes', async () => { - const screen = render(PropsReactivity) + const screen = await render(PropsReactivity) const toggleButton = screen.getByText('Toggle statusbar') expect( diff --git a/examples/sveltekit/vitest.config.ts b/examples/sveltekit/vitest.config.ts index 924d3f7db..5a22254af 100644 --- a/examples/sveltekit/vitest.config.ts +++ b/examples/sveltekit/vitest.config.ts @@ -1,5 +1,6 @@ import { sveltekit } from '@sveltejs/kit/vite' import tailwindcss from '@tailwindcss/vite' +import { playwright } from '@vitest/browser-playwright' import { defineConfig } from 'vite' export default defineConfig({ @@ -7,7 +8,7 @@ export default defineConfig({ test: { browser: { enabled: true, - provider: 'playwright', + provider: playwright(), instances: [{ browser: 'chromium' }], }, }, diff --git a/examples/transloadit/index.html b/examples/transloadit/index.html index a3919ae1f..a9e0b9c1f 100644 --- a/examples/transloadit/index.html +++ b/examples/transloadit/index.html @@ -1,5 +1,5 @@ - + @@ -140,7 +140,7 @@ This API is a one-shot upload UI using a modal overlay. Call the function and receive a listen to an event with upload results ✌️

- +

uppy.upload()

An <input type=file> backed by uppy.upload():

diff --git a/examples/transloadit/main.js b/examples/transloadit/main.js index 7853376a3..88720ac57 100644 --- a/examples/transloadit/main.js +++ b/examples/transloadit/main.js @@ -50,9 +50,11 @@ const formUppy = new Uppy({ }) .use(Transloadit, { waitForEncoding: true, - params: { - auth: { key: TRANSLOADIT_KEY }, - template_id: TEMPLATE_ID, + assemblyOptions: { + params: { + auth: { key: TRANSLOADIT_KEY }, + template_id: TEMPLATE_ID, + }, }, }) @@ -100,9 +102,11 @@ const formUppyWithDashboard = new Uppy({ }) .use(Transloadit, { waitForEncoding: true, - params: { - auth: { key: TRANSLOADIT_KEY }, - template_id: TEMPLATE_ID, + assemblyOptions: { + params: { + auth: { key: TRANSLOADIT_KEY }, + template_id: TEMPLATE_ID, + }, }, }) @@ -129,9 +133,11 @@ const dashboard = new Uppy({ .use(ImageEditor, { target: Dashboard }) .use(Transloadit, { waitForEncoding: true, - params: { - auth: { key: TRANSLOADIT_KEY }, - template_id: TEMPLATE_ID, + assemblyOptions: { + params: { + auth: { key: TRANSLOADIT_KEY }, + template_id: TEMPLATE_ID, + }, }, }) @@ -151,9 +157,11 @@ const dashboardModal = new Uppy({ .use(ImageEditor, { target: Dashboard }) .use(Transloadit, { waitForEncoding: true, - params: { - auth: { key: TRANSLOADIT_KEY }, - template_id: TEMPLATE_ID, + assemblyOptions: { + params: { + auth: { key: TRANSLOADIT_KEY }, + template_id: TEMPLATE_ID, + }, }, }) @@ -182,9 +190,11 @@ const uppyWithoutUI = new Uppy({ }, }).use(Transloadit, { waitForEncoding: true, - params: { - auth: { key: TRANSLOADIT_KEY }, - template_id: TEMPLATE_ID, + assemblyOptions: { + params: { + auth: { key: TRANSLOADIT_KEY }, + template_id: TEMPLATE_ID, + }, }, }) diff --git a/examples/transloadit/package.json b/examples/transloadit/package.json index 6072b43ab..bb08b521e 100644 --- a/examples/transloadit/package.json +++ b/examples/transloadit/package.json @@ -15,7 +15,7 @@ "@uppy/remote-sources": "workspace:*", "@uppy/transloadit": "workspace:*", "@uppy/webcam": "workspace:*", - "express": "^4.22.0", + "express": "^5.2.1", "he": "^1.2.0" }, "private": true, diff --git a/examples/transloadit/server.js b/examples/transloadit/server.js index 765301bd5..c71994b0e 100755 --- a/examples/transloadit/server.js +++ b/examples/transloadit/server.js @@ -36,7 +36,7 @@ function Footer() { } function FormFields(fields) { - // biome-ignore lint/nursery/noNestedComponentDefinitions: not a react component + // biome-ignore lint/correctness/noNestedComponentDefinitions: not a react component function Field([name, value]) { if (name === 'transloadit') return '' let isValueJSON = false @@ -76,7 +76,7 @@ function FormFields(fields) { } function UploadsList(uploads) { - // biome-ignore lint/nursery/noNestedComponentDefinitions: not a react component + // biome-ignore lint/correctness/noNestedComponentDefinitions: not a react component function Upload(upload) { return `
  • ${e(upload.name)}
  • ` } @@ -89,12 +89,12 @@ function UploadsList(uploads) { } function ResultsList(results) { - // biome-ignore lint/nursery/noNestedComponentDefinitions: not a react component + // biome-ignore lint/correctness/noNestedComponentDefinitions: not a react component function Result(result) { return `
  • ${e(result.name)} View
  • ` } - // biome-ignore lint/nursery/noNestedComponentDefinitions: not a react component + // biome-ignore lint/correctness/noNestedComponentDefinitions: not a react component function ResultsSection(stepName) { return `

    ${e(stepName)}

    diff --git a/examples/vue/package.json b/examples/vue/package.json index a0f42e3db..4d2c046b1 100644 --- a/examples/vue/package.json +++ b/examples/vue/package.json @@ -22,11 +22,13 @@ "devDependencies": { "@tailwindcss/vite": "^4.1.11", "@vitejs/plugin-vue": "^6.0.1", - "@vitest/browser": "^3.2.4", - "playwright": "1.57.0", + "@vitest/browser": "^4.1.6", + "@vitest/browser-playwright": "^4.1.6", + "msw": "^2.10.4", + "playwright": "1.60.0", "tailwindcss": "^4.0.0", "vite": "^7.1.11", - "vitest": "^3.2.4", - "vitest-browser-vue": "^1.0.0" + "vitest": "^4.1.6", + "vitest-browser-vue": "^2.1.0" } } diff --git a/examples/vue/src/App.vue b/examples/vue/src/App.vue index 6aa4c8167..ad77e76b3 100644 --- a/examples/vue/src/App.vue +++ b/examples/vue/src/App.vue @@ -19,18 +19,23 @@ v-if="modalPlugin === 'screen-capture'" :close="closeModal" /> +

    With list

    - +

    With grid

    - +
    @@ -42,7 +47,8 @@ + diff --git a/examples/vue/src/Dropzone.vue b/examples/vue/src/Dropzone.vue index c36d0a9a9..4bb75fd80 100644 --- a/examples/vue/src/Dropzone.vue +++ b/examples/vue/src/Dropzone.vue @@ -7,7 +7,7 @@ >
    - - - - - - - -