diff --git a/.eslintrc.js b/.eslintrc.js index 3814d3c9f5..916604aa0f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -243,6 +243,7 @@ module.exports = { 'packages/@uppy/webcam/src/**/*.js', 'packages/@uppy/xhr-upload/src/**/*.js', 'packages/@uppy/zoom/src/**/*.js', + 'website/src/examples/*/*.es6', ], parser: 'espree', parserOptions: { diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a23ea60e4d..f25844283b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -48,6 +48,12 @@ To start the testing suite run: yarn e2e +This will run Cypress in watch-mode, and it will pick up and rebuild any changes to JS files. If you need to change other files (like CSS for example), you need to run the respective `yarn build:*` scripts. + +Alternatively the following command is the same as the above, except it doesn't run `build` first: + + yarn e2e:skip-build + To generate the boilerplate for a new test run: yarn e2e:generate @@ -94,7 +100,7 @@ The following steps describe the actions that take place when a user Authenticat ### Instagram integration -Even though facebook [allows using](https://developers.facebook.com/blog/post/2018/06/08/enforce-https-facebook-login/) http://localhost in dev mode, Instagram doesn’t seem to support that, and seems to need a publically available domain name with HTTPS. +Even though facebook [allows using](https://developers.facebook.com/blog/post/2018/06/08/enforce-https-facebook-login/) http://localhost in dev mode, Instagram doesn’t seem to support that, and seems to need a publically available domain name with HTTPS. So we will tunnel requests to localhost using `ngrok`. Make sure that you are using a development facebook app at @@ -103,6 +109,8 @@ Go to “Instagram Basic Display” and find `Instagram App ID` and `Instagram A COMPANION_INSTAGRAM_KEY="Instagram App ID" COMPANION_INSTAGRAM_SECRET="Instagram App Secret" +**Note!** `ngrok` seems to be blocked by Instagram now, so you may have to find an alternative. + Run ```bash @@ -130,6 +138,14 @@ Tester invites -> Accept Now you should be able to test the Instagram integration. +## Zoom + +See above Instagram instructions for setting up a tunnel, but replace `instagram` with `zoom` in the URL. Note that **you also have to add the OAuth redirect URL to `OAuth allow list`** in the Zoom Oauth app settings or it will not work. + +Add the following scopes: `recording:read`, `user:read`, `user_info:read` + +To test recording a meeting, you need to sign up for a Zoom Pro trial (can be cancelled later), for example using their iOS app. + ## Releases Before doing a release, check that the examples on the website work: diff --git a/.github/workflows/release-beta-candidate.yml b/.github/workflows/release-beta-candidate.yml deleted file mode 100644 index fee7075e87..0000000000 --- a/.github/workflows/release-beta-candidate.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Release beta candidate -on: - push: - branches: release-beta - -env: - BETA_BRANCH: 3.x - -jobs: - prepare-beta-release: - name: Prepare release candidate Pull Request - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - branch: release-beta - fetch-depth: 3 # the prepare commit, the merge commit, and the base ones. - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(corepack yarn config get cacheFolder)" - - - uses: actions/cache@v3 - 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@v3 - with: - node-version: lts/* - - name: Install dependencies - run: corepack yarn install --immutable - - name: Bump candidate packages version - run: corepack yarn version apply --all --prerelease=beta.%n --json | jq -s > releases.json - - name: Prepare changelog - run: corepack yarn workspace @uppy-dev/release update-changelogs releases.json | xargs git add - - name: Update CDN URLs - run: corepack yarn workspace @uppy-dev/release update-version-URLs | xargs git add - - name: Stage changes and remove temp files - run: | - git rm -rf .yarn/versions - git rm CHANGELOG.next.md - jq -r 'map(.cwd) | join("\n")' < releases.json | awk '{ print "git add " $0 "/package.json" }' | sh - - name: Commit - run: | - echo "Release: uppy@$(jq -r 'map(select(.ident == "uppy"))[0].newVersion' < releases.json)" > commitMessage - echo >> commitMessage - echo "This is a release candidate for the following packages:" >> commitMessage - echo >> commitMessage - jq -r 'map("- `"+.ident+"`: "+.oldVersion+" -> "+.newVersion) | join("\n") ' < releases.json >> commitMessage - git config --global user.email "actions@github.com" - git config --global user.name "GitHub Actions" - git commit -n --amend --file commitMessage - - name: Open Pull Request - id: pr_opening - run: | - git push origin HEAD:release-candidate - gh api repos/${{ github.repository }}/pulls \ - -F base="${{ env.BETA_BRANCH }}" \ - -F head="release-candidate" \ - -F title="$(head -1 commitMessage)" \ - -F body="$(git --no-pager diff HEAD^ -- CHANGELOG.md | awk '{ if( substr($0,0,1) == "+" && $1 != "+##" && $1 != "+Released:" && $1 != "+++" ) { print substr($0,2) } }')" \ - --jq '.number | tostring | "##[set-output name=pr_number;]"+.' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Assign to the releaser - run: echo '{"assignees":[${{ toJSON(github.actor) }}]}' | gh api repos/${{ github.repository }}/issues/${{ steps.pr_opening.outputs.pr_number }}/assignees --input - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Enable Release workflow - run: gh workflow enable Release --repo ${{ github.repository }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index 327a1522ff..fee7075e87 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -1,23 +1,21 @@ -name: Release candidate +name: Release beta candidate on: push: - branches: release + branches: release-beta + +env: + BETA_BRANCH: 3.x jobs: - prepare-release: + prepare-beta-release: name: Prepare release candidate Pull Request runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: - branch: release - - name: Rebase - run: | - git fetch origin HEAD --depth=1 - git config --global user.email "actions@github.com" - git config --global user.name "GitHub Actions" - git rebase FETCH_HEAD + branch: release-beta + fetch-depth: 3 # the prepare commit, the merge commit, and the base ones. - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(corepack yarn config get cacheFolder)" @@ -36,7 +34,7 @@ jobs: - name: Install dependencies run: corepack yarn install --immutable - name: Bump candidate packages version - run: corepack yarn version apply --all --json | jq -s > releases.json + run: corepack yarn version apply --all --prerelease=beta.%n --json | jq -s > releases.json - name: Prepare changelog run: corepack yarn workspace @uppy-dev/release update-changelogs releases.json | xargs git add - name: Update CDN URLs @@ -53,13 +51,15 @@ jobs: echo "This is a release candidate for the following packages:" >> commitMessage echo >> commitMessage jq -r 'map("- `"+.ident+"`: "+.oldVersion+" -> "+.newVersion) | join("\n") ' < releases.json >> commitMessage + git config --global user.email "actions@github.com" + git config --global user.name "GitHub Actions" git commit -n --amend --file commitMessage - name: Open Pull Request id: pr_opening run: | git push origin HEAD:release-candidate gh api repos/${{ github.repository }}/pulls \ - -F base="$(gh api /repos/${{ github.repository }} | jq -r .default_branch)" \ + -F base="${{ env.BETA_BRANCH }}" \ -F head="release-candidate" \ -F title="$(head -1 commitMessage)" \ -F body="$(git --no-pager diff HEAD^ -- CHANGELOG.md | awk '{ if( substr($0,0,1) == "+" && $1 != "+##" && $1 != "+Released:" && $1 != "+++" ) { print substr($0,2) } }')" \ diff --git a/.yarn/patches/npm-auth-to-token-npm-1.0.0-c288ce201f b/.yarn/patches/npm-auth-to-token-npm-1.0.0-c288ce201f deleted file mode 100644 index b2c532fc6b..0000000000 --- a/.yarn/patches/npm-auth-to-token-npm-1.0.0-c288ce201f +++ /dev/null @@ -1,79 +0,0 @@ -diff --git a/cli.js b/cli.js -index 43b59bb85665ccff53a62c86162093dd1d64ba6d..40bf4d43317a2ffb1dad0c2f7e1f02f4421469a3 100755 ---- a/cli.js -+++ b/cli.js -@@ -1,45 +1,43 @@ - #!/usr/bin/env node - --const program = require('commander'); --const { version } = require('./package.json'); --var RegClient = require('npm-registry-client'); --const fs = require('fs'); -+"use strict"; -+ -+const program = require("commander"); -+const { version } = require("./package.json"); -+var RegClient = require("npm-registry-client"); - var client = new RegClient(); - let args = process.argv; - - if (args.length === 3) { -- args = [args[0], args[1]].concat(args[2].split(' ')); -+ args = [args[0], args[1]].concat(args[2].split(" ")); - } - - program - .version(version) -- .option('-u, --username ', 'username') -- .option('-p, --password ', 'password') -- .option('-e, --email ', 'email') -- .option('-r, --registry ', 'registry', 'https://registry.npmjs.org/') -+ .option("-u, --username ", "username") -+ .option("-p, --password ", "password") -+ .option("-e, --email ", "email") -+ .option( -+ "-r, --registry ", -+ "registry", -+ "https://registry.npmjs.org/" -+ ) - .parse(args); - --const { -- username, -- password, -- email, -- registry --} = program; -+const { username, password, email, registry } = program; - --client.adduser(registry, { -- auth: { -- username, -- password, -- email, -- alwaysAuth: true -- } --}, (err, res) => { -- if (err) throw err; -- const path = `${process.cwd()}/.npmrc`; -- let base = registry.substr(registry.indexOf('/'), registry.length); -- if (base.lastIndexOf('/') !== registry.length - 1) { -- base += '/'; -+client.adduser( -+ registry, -+ { -+ auth: { -+ username, -+ password, -+ email, -+ alwaysAuth: true, -+ }, -+ }, -+ (err, res) => { -+ if (err) throw err; -+ console.log(res.token); - } -- fs.writeFileSync(path, `registry=${registry}\n${base}:_authToken=${res.token}`); -- console.log('Done'); --}); -+); diff --git a/.yarn/patches/preact-npm-10.10.0-dd04de05e8.patch b/.yarn/patches/preact-npm-10.10.0-dd04de05e8.patch new file mode 100644 index 0000000000..e4029d65d8 --- /dev/null +++ b/.yarn/patches/preact-npm-10.10.0-dd04de05e8.patch @@ -0,0 +1,12 @@ +diff --git a/package.json b/package.json +index 60279c24a08b808ffbf7dc64a038272bddb6785d..71cb8aa038daeeb7edf43564ed78a219003a0c99 100644 +--- a/package.json ++++ b/package.json +@@ -9,6 +9,7 @@ + "umd:main": "dist/preact.umd.js", + "unpkg": "dist/preact.min.js", + "source": "src/index.js", ++ "type": "module", + "exports": { + ".": { + "types": "./src/index.d.ts", diff --git a/.yarnrc.yml b/.yarnrc.yml index 93126352be..7745cf9592 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -5,6 +5,7 @@ changesetBaseRefs: initScope: uppy +enableGlobalCache: false nodeLinker: node-modules plugins: diff --git a/BUNDLE-README.md b/BUNDLE-README.md index 1890c1b03c..8c39367cfa 100644 --- a/BUNDLE-README.md +++ b/BUNDLE-README.md @@ -1,7 +1,7 @@ # Uppy 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. +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 a bundler like Webpack so that you can create a smaller custom build with only the diff --git a/CHANGELOG.md b/CHANGELOG.md index fef6fd8b27..312212b02b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,62 @@ Please add your entries in this format: In the current stage we aim to release a new version at least every month. +## 3.0.0-beta.5 + +Released: 2022-08-16 + +| Package | Version | Package | Version | +| ------------------------- | ------------ | ------------------------- | ------------ | +| @uppy/angular | 1.0.0-beta.1 | @uppy/onedrive | 3.0.0-beta.2 | +| @uppy/audio | 1.0.0-beta.2 | @uppy/progress-bar | 3.0.0-beta.2 | +| @uppy/aws-s3 | 3.0.0-beta.3 | @uppy/provider-views | 3.0.0-beta.3 | +| @uppy/aws-s3-multipart | 3.0.0-beta.4 | @uppy/react | 3.0.0-beta.4 | +| @uppy/box | 2.0.0-beta.2 | @uppy/redux-dev-tools | 3.0.0-beta.2 | +| @uppy/companion | 4.0.0-beta.4 | @uppy/remote-sources | 1.0.0-beta.4 | +| @uppy/companion-client | 3.0.0-beta.2 | @uppy/screen-capture | 3.0.0-beta.3 | +| @uppy/compressor | 1.0.0-beta.3 | @uppy/status-bar | 3.0.0-beta.3 | +| @uppy/core | 3.0.0-beta.4 | @uppy/store-default | 3.0.0-beta.3 | +| @uppy/dashboard | 3.0.0-beta.4 | @uppy/store-redux | 3.0.0-beta.3 | +| @uppy/drag-drop | 3.0.0-beta.2 | @uppy/svelte | 2.0.0-beta.2 | +| @uppy/drop-target | 2.0.0-beta.3 | @uppy/thumbnail-generator | 3.0.0-beta.2 | +| @uppy/dropbox | 3.0.0-beta.2 | @uppy/transloadit | 3.0.0-beta.5 | +| @uppy/facebook | 3.0.0-beta.2 | @uppy/tus | 3.0.0-beta.3 | +| @uppy/file-input | 3.0.0-beta.2 | @uppy/unsplash | 3.0.0-beta.2 | +| @uppy/form | 3.0.0-beta.2 | @uppy/url | 3.0.0-beta.3 | +| @uppy/golden-retriever | 3.0.0-beta.2 | @uppy/utils | 5.0.0-beta.1 | +| @uppy/google-drive | 3.0.0-beta.2 | @uppy/vue | 1.0.0-beta.2 | +| @uppy/image-editor | 2.0.0-beta.3 | @uppy/webcam | 3.0.0-beta.3 | +| @uppy/informer | 3.0.0-beta.3 | @uppy/xhr-upload | 3.0.0-beta.3 | +| @uppy/instagram | 3.0.0-beta.2 | @uppy/zoom | 2.0.0-beta.2 | +| @uppy/locales | 3.0.0-beta.4 | uppy | 3.0.0-beta.5 | + +- meta: prepare release workflow for beta versions (Antoine du Hamel) +- @uppy/provider-views: Reset filter input correctly in provider views (Merlijn Vos / #3978) +- @uppy/aws-s3-multipart: Fix when using Companion (Merlijn Vos / #3969) +- @uppy/companion: Companion: bring back default upload protocol (Mikael Finstad / #3967) +- meta: Update CONTRIBUTING.md (Mikael Finstad / #3966) +- meta: fix contributing link (Mikael Finstad / #3968) +- @uppy/companion: enforce usage of uploadUrls (Mikael Finstad / #3965) +- @uppy/utils: Fix webp mimetype (Merlijn Vos / #3961) +- @uppy/locales: Add compressor string translation to Japanese locale (kenken / #3963) +- meta: Fix statement about cropping images in README.md (Mikael Finstad / #3964) +- @uppy/aws-s3-multipart: Fix race condition in `#uploadParts` (Morgan Zolob / #3955) +- @uppy/provider-views: core validateRestrictions: return error directly vs the result/reason obj (Artur Paikin / #3951) +- @uppy/aws-s3: Export AwsS3UploadParameters & AwsS3Options interfaces (Antonina Vertsinskaya / #3956) +- website: convert all website examples to ESM (Antoine du Hamel / #3957) +- @uppy/companion: fix crash if redis disconnects (Mikael Finstad / #3954) +- @uppy/companion: upgrade `ws` version (Antoine du Hamel / #3949) +- @uppy/companion: sort Dropbox response & refactor to async/await (Mikael Finstad / #3897) +- @uppy/utils: modernize `getDroppedFiles` (Antoine du Hamel / #3534) +- @uppy/companion: fix default getKey for non-standalone too (Mikael Finstad / #3945) +- @uppy/aws-s3-multipart: ignore exception inside `abortMultipartUpload` (Antoine du Hamel / #3950) +- @uppy/companion: remove `isobject` from dependencies (Antoine du Hamel / #3948) +- @uppy/compressor: Fix Compressor being broken when no name is in the compressed blob (Artur Paikin / #3947) +- @uppy/core,@uppy/react: Fix all breaking todo comments for 3.0 (Merlijn Vos / #3907) +- @uppy/companion: show deprecation message when using legacy s3 options (Antoine du Hamel / #3944) +- example: fix aws-companion example (Antoine du Hamel / #3850) + + ## 3.0.0-beta.4 Released: 2022-08-03 diff --git a/README.md b/README.md index e1e610d344..eed6c2f1c9 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ const uppy = new Uppy({ autoProceed: false }) $ npm install @uppy/core @uppy/dashboard @uppy/tus ``` -Add CSS [uppy.min.css](https://releases.transloadit.com/uppy/v3.0.0-beta.4/uppy.min.css), either to your HTML page’s `` or include in JS, if your bundler of choice supports it. +Add CSS [uppy.min.css](https://releases.transloadit.com/uppy/v3.0.0-beta.5/uppy.min.css), either to your HTML page’s `` or include in JS, if your bundler of choice supports it. Alternatively, you can also use a pre-built bundle from Transloadit’s CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. @@ -75,10 +75,10 @@ Alternatively, you can also use a pre-built bundle from Transloadit’s CDN: Edg ```html - + - +
@@ -184,7 +184,7 @@ If you’re using Uppy from CDN, those polyfills are already included in the leg bundle, so no need to include anything additionally: ```html - + ``` ## FAQ @@ -194,7 +194,8 @@ bundle, so no need to include anything additionally: Having no JavaScript beats having a lot of it, so that’s a fair question! Running an uploading & encoding business for ten years though we found that in cases, the file input leaves some to be desired: * We received complaints about broken uploads and found that resumable uploads are important, especially for big files and to be inclusive towards people on poorer connections (we also launched [tus.io](https://tus.io) to attack that problem). Uppy uploads can survive network outages and browser crashes or accidental navigate-aways. -* Uppy supports editing meta information before uploading (such as cropping of images). +* 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 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. * Accurate upload progress reporting is an issue on many platforms. * Some file validation — size, type, number of files — can be done on the client with Uppy. diff --git a/babel.config.js b/babel.config.js index 5237096e6d..d63a73d16e 100644 --- a/babel.config.js +++ b/babel.config.js @@ -16,7 +16,7 @@ module.exports = (api) => { targets, useBuiltIns: false, // Don't add polyfills automatically. // We can uncomment the following line if we start adding polyfills to the non-legacy dist files. - // corejs: { version: '3.15', proposals: true }, + // corejs: { version: '3.24', proposals: true }, modules: false, }], ], diff --git a/bin/build-bundle.mjs b/bin/build-bundle.mjs index 3eee49734c..3fd85eb1cd 100644 --- a/bin/build-bundle.mjs +++ b/bin/build-bundle.mjs @@ -63,7 +63,7 @@ const methods = [ loose: false, targets: { ie:11 }, useBuiltIns: 'entry', - corejs: { version: '3.15', proposals: true }, + corejs: { version: '3.24', proposals: true }, }]], }, })], diff --git a/bin/build-css.js b/bin/build-css.js index bcd73b987c..c23ccee137 100644 --- a/bin/build-css.js +++ b/bin/build-css.js @@ -4,7 +4,6 @@ const autoprefixer = require('autoprefixer') const postcssLogical = require('postcss-logical') const postcssDirPseudoClass = require('postcss-dir-pseudo-class') const cssnano = require('cssnano') -const chalk = require('chalk') const { promisify } = require('node:util') const fs = require('node:fs') const path = require('node:path') @@ -15,12 +14,14 @@ const renderScss = promisify(sass.render) const { mkdir, writeFile } = fs.promises const cwd = process.cwd() +let chalk function handleErr (err) { console.error(chalk.red('✗ Error:'), chalk.red(err.message)) } async function compileCSS () { + ({ default:chalk } = await import('chalk')) const files = await glob('packages/{,@uppy/}*/src/style.scss') for (const file of files) { diff --git a/bin/build-lib.js b/bin/build-lib.js index 23dd6054ab..69985ef2d6 100644 --- a/bin/build-lib.js +++ b/bin/build-lib.js @@ -1,4 +1,3 @@ -const chalk = require('chalk') const babel = require('@babel/core') const t = require('@babel/types') const { promisify } = require('node:util') @@ -118,7 +117,8 @@ async function buildLib () { }, }] : undefined const { code, map } = await babel.transformFileAsync(file, { sourceMaps: true, plugins }) - await Promise.all([ + const [{ default: chalk }] = await Promise.all([ + import('chalk'), writeFile(libFile, code), writeFile(`${libFile}.map`, JSON.stringify(map)), ]) diff --git a/e2e/clients/dashboard-xhr/app.js b/e2e/clients/dashboard-xhr/app.js new file mode 100644 index 0000000000..88300630a3 --- /dev/null +++ b/e2e/clients/dashboard-xhr/app.js @@ -0,0 +1,18 @@ +import { Uppy } from '@uppy/core' +import Dashboard from '@uppy/dashboard' +import XHRUpload from '@uppy/xhr-upload' +import Unsplash from '@uppy/unsplash' +import Url from '@uppy/url' + +import '@uppy/core/dist/style.css' +import '@uppy/dashboard/dist/style.css' + +const companionUrl = 'http://localhost:3020' +const uppy = new Uppy() + .use(Dashboard, { target: '#app', inline: true }) + .use(XHRUpload, { endpoint: 'https://xhr-server.herokuapp.com/upload', limit: 6 }) + .use(Url, { target: Dashboard, companionUrl }) + .use(Unsplash, { target: Dashboard, companionUrl }) + +// Keep this here to access uppy in tests +window.uppy = uppy diff --git a/e2e/clients/dashboard-xhr/index.html b/e2e/clients/dashboard-xhr/index.html new file mode 100644 index 0000000000..48832c7ffe --- /dev/null +++ b/e2e/clients/dashboard-xhr/index.html @@ -0,0 +1,11 @@ + + + + + dashboard-xhr + + + +
+ + diff --git a/e2e/clients/index.html b/e2e/clients/index.html index 099a19176d..695aa3277c 100644 --- a/e2e/clients/index.html +++ b/e2e/clients/index.html @@ -12,6 +12,7 @@

Test apps

  • react
  • dashboard-transloadit
  • dashboard-tus
  • +
  • dashboard-xhr
  • dashboard-ui
  • dashboard-vue
  • diff --git a/e2e/cypress/fixtures/images/cat-symbolic-link b/e2e/cypress/fixtures/images/cat-symbolic-link new file mode 120000 index 0000000000..d9dd9f2118 --- /dev/null +++ b/e2e/cypress/fixtures/images/cat-symbolic-link @@ -0,0 +1 @@ +./cat.jpg \ No newline at end of file diff --git a/e2e/cypress/fixtures/images/cat-symbolic-link.jpg b/e2e/cypress/fixtures/images/cat-symbolic-link.jpg new file mode 120000 index 0000000000..d9dd9f2118 --- /dev/null +++ b/e2e/cypress/fixtures/images/cat-symbolic-link.jpg @@ -0,0 +1 @@ +./cat.jpg \ No newline at end of file diff --git a/e2e/cypress/integration/dashboard-tus.spec.ts b/e2e/cypress/integration/dashboard-tus.spec.ts index 4d44137146..d88891ab1e 100644 --- a/e2e/cypress/integration/dashboard-tus.spec.ts +++ b/e2e/cypress/integration/dashboard-tus.spec.ts @@ -1,5 +1,7 @@ import type BaseTus from '@uppy/tus' +import { interceptCompanionUrlRequest, interceptCompanionUnsplashRequest, runRemoteUrlImageUploadTest, runRemoteUnsplashUploadTest } from './reusable-tests' + type Tus = BaseTus & { requests: { isPaused: boolean } } @@ -12,8 +14,8 @@ describe('Dashboard with Tus', () => { cy.visit('/dashboard-tus') cy.get('.uppy-Dashboard-input:first').as('file-input') cy.intercept('/files/*').as('tus') - cy.intercept('http://localhost:3020/url/*').as('url') - cy.intercept('http://localhost:3020/search/unsplash/*').as('unsplash') + interceptCompanionUrlRequest() + interceptCompanionUnsplashRequest() }) it('should upload cat image successfully', () => { @@ -53,33 +55,10 @@ describe('Dashboard with Tus', () => { ) it('should upload remote image with URL plugin', () => { - cy.get('[data-cy="Url"]').click() - cy.get('.uppy-Url-input').type('https://raw.githubusercontent.com/transloadit/uppy/main/e2e/cypress/fixtures/images/cat.jpg') - cy.get('.uppy-Url-importButton').click() - cy.get('.uppy-StatusBar-actionBtn--upload').click() - cy.wait('@url') - cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + runRemoteUrlImageUploadTest() }) it('should upload remote image with Unsplash plugin', () => { - cy.get('[data-cy="Unsplash"]').click() - cy.get('.uppy-SearchProvider-input').type('book') - cy.get('.uppy-SearchProvider-searchButton').click() - cy.wait('@unsplash') - // Test that the author link is visible - cy.get('.uppy-ProviderBrowserItem') - .first() - .within(() => { - cy.root().click() - // We have hover states that show the author - // but we don't have hover in e2e, so we focus after the click - // to get the same effect. Also tests keyboard users this way. - cy.get('input[type="checkbox"]').focus() - cy.get('a').should('have.css', 'display', 'block') - }) - cy.get('.uppy-c-btn-primary').click() - cy.get('.uppy-StatusBar-actionBtn--upload').click() - cy.wait('@unsplash') - cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + runRemoteUnsplashUploadTest() }) }) diff --git a/e2e/cypress/integration/dashboard-ui.spec.ts b/e2e/cypress/integration/dashboard-ui.spec.ts index f68ec8b156..f322ead87f 100644 --- a/e2e/cypress/integration/dashboard-ui.spec.ts +++ b/e2e/cypress/integration/dashboard-ui.spec.ts @@ -2,6 +2,7 @@ describe('dashboard-ui', () => { beforeEach(() => { cy.visit('/dashboard-ui') cy.get('.uppy-Dashboard-input:first').as('file-input') + cy.get('.uppy-Dashboard-AddFiles').as('drop-target') }) it('should not throw when calling uppy.close()', () => { @@ -18,4 +19,19 @@ describe('dashboard-ui', () => { .should('have.length', 2) .each((element) => expect(element).attr('src').to.include('blob:')) }) + + it('should support drag&drop', () => { + cy.get('@drop-target').selectFile([ + 'cypress/fixtures/images/cat.jpg', + 'cypress/fixtures/images/cat-symbolic-link', + 'cypress/fixtures/images/cat-symbolic-link.jpg', + 'cypress/fixtures/images/traffic.jpg', + ], { action: 'drag-drop' }) + + cy.get('.uppy-Dashboard-Item') + .should('have.length', 4) + cy.get('.uppy-Dashboard-Item-previewImg') + .should('have.length', 3) + .each((element) => expect(element).attr('src').to.include('blob:')) + }) }) diff --git a/e2e/cypress/integration/dashboard-xhr.spec.ts b/e2e/cypress/integration/dashboard-xhr.spec.ts new file mode 100644 index 0000000000..ea7f706060 --- /dev/null +++ b/e2e/cypress/integration/dashboard-xhr.spec.ts @@ -0,0 +1,17 @@ +import { interceptCompanionUrlRequest, interceptCompanionUnsplashRequest, runRemoteUrlImageUploadTest, runRemoteUnsplashUploadTest } from './reusable-tests' + +describe('Dashboard with XHR', () => { + beforeEach(() => { + cy.visit('/dashboard-xhr') + interceptCompanionUrlRequest() + interceptCompanionUnsplashRequest() + }) + + it('should upload remote image with URL plugin', () => { + runRemoteUrlImageUploadTest() + }) + + it('should upload remote image with Unsplash plugin', () => { + runRemoteUnsplashUploadTest() + }) +}) diff --git a/e2e/cypress/integration/reusable-tests.ts b/e2e/cypress/integration/reusable-tests.ts new file mode 100644 index 0000000000..291d0fa2aa --- /dev/null +++ b/e2e/cypress/integration/reusable-tests.ts @@ -0,0 +1,35 @@ +/* global cy */ + +export const interceptCompanionUrlRequest = () => cy.intercept('http://localhost:3020/url/*').as('url') +export const interceptCompanionUnsplashRequest = () => cy.intercept('http://localhost:3020/search/unsplash/*').as('unsplash') + +export function runRemoteUrlImageUploadTest () { + cy.get('[data-cy="Url"]').click() + cy.get('.uppy-Url-input').type('https://raw.githubusercontent.com/transloadit/uppy/main/e2e/cypress/fixtures/images/cat.jpg') + cy.get('.uppy-Url-importButton').click() + cy.get('.uppy-StatusBar-actionBtn--upload').click() + cy.wait('@url') + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') +} + +export function runRemoteUnsplashUploadTest () { + cy.get('[data-cy="Unsplash"]').click() + cy.get('.uppy-SearchProvider-input').type('book') + cy.get('.uppy-SearchProvider-searchButton').click() + cy.wait('@unsplash') + // Test that the author link is visible + cy.get('.uppy-ProviderBrowserItem') + .first() + .within(() => { + cy.root().click() + // We have hover states that show the author + // but we don't have hover in e2e, so we focus after the click + // to get the same effect. Also tests keyboard users this way. + cy.get('input[type="checkbox"]').focus() + cy.get('a').should('have.css', 'display', 'block') + }) + cy.get('.uppy-c-btn-primary').click() + cy.get('.uppy-StatusBar-actionBtn--upload').click() + cy.wait('@unsplash') + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') +} diff --git a/e2e/package.json b/e2e/package.json index 3642f81205..b05a2ea33b 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -51,7 +51,7 @@ "prompts": "^2.4.2", "react": "^18.1.0", "react-dom": "^18.1.0", - "typescript": "^4.5.4", - "vue": "next" + "typescript": "~4.7", + "vue": "^3.2.33" } } diff --git a/examples/angular-example/package.json b/examples/angular-example/package.json index bd5f225c7c..5cd28d1841 100644 --- a/examples/angular-example/package.json +++ b/examples/angular-example/package.json @@ -45,7 +45,7 @@ "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsdoc": "^38.0.0", + "eslint-plugin-jsdoc": "^39.0.0", "eslint-plugin-prefer-arrow": "^1.2.3", "jasmine-core": "~3.6.0", "jasmine-spec-reporter": "~5.0.0", @@ -56,6 +56,6 @@ "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", "ts-node": "~8.3.0", - "typescript": "~4.4" + "typescript": "~4.7" } } diff --git a/examples/aws-companion/package.json b/examples/aws-companion/package.json index d95be1e4ad..ebf9541750 100644 --- a/examples/aws-companion/package.json +++ b/examples/aws-companion/package.json @@ -18,7 +18,7 @@ "express": "^4.18.1", "express-session": "^1.17.3", "npm-run-all": "^4.1.5", - "vite": "^2.7.1" + "vite": "^3.0.0" }, "private": true, "engines": { diff --git a/examples/aws-presigned-url/package.json b/examples/aws-presigned-url/package.json index 59bdc2ecd5..dc85669961 100644 --- a/examples/aws-presigned-url/package.json +++ b/examples/aws-presigned-url/package.json @@ -8,7 +8,7 @@ "uppy": "workspace:*" }, "devDependencies": { - "esbuild": "^0.14.1" + "esbuild": "^0.15.1" }, "private": true, "type": "module", diff --git a/examples/cdn-example/index.html b/examples/cdn-example/index.html index f6cb0fa819..b355728ca8 100644 --- a/examples/cdn-example/index.html +++ b/examples/cdn-example/index.html @@ -4,7 +4,7 @@ - + @@ -16,7 +16,7 @@ Dashboard, Webcam, Tus, - } from "https://releases.transloadit.com/uppy/v3.0.0-beta.4/uppy.min.mjs"; + } from "https://releases.transloadit.com/uppy/v3.0.0-beta.5/uppy.min.mjs"; const uppy = new Core.Uppy({ debug: true, autoProceed: false }) .use(Dashboard, { trigger: "#uppyModalOpener" }) @@ -29,7 +29,7 @@ - + + + + ``` Then, a global `Robodog` variable will be available. For usage instructions, please see the [main Robodog documentation](https://uppy.io/docs/robodog). diff --git a/packages/@uppy/robodog/package.json b/packages/@uppy/robodog/package.json index 90701a7342..7641bb86a8 100644 --- a/packages/@uppy/robodog/package.json +++ b/packages/@uppy/robodog/package.json @@ -48,10 +48,9 @@ }, "devDependencies": { "abortcontroller-polyfill": "^1.7.3", - "core-js": "~3.19.3", + "core-js": "~3.24.0", "md-gum-polyfill": "^1.0.0", "resize-observer-polyfill": "^1.5.1", "whatwg-fetch": "^3.6.2" - }, - "stableVersion": "2.7.0" + } } diff --git a/packages/@uppy/screen-capture/package.json b/packages/@uppy/screen-capture/package.json index a11e3a1ef6..6a28cb8700 100644 --- a/packages/@uppy/screen-capture/package.json +++ b/packages/@uppy/screen-capture/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/screen-capture", "description": "Uppy plugin that captures video from display or application.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "style": "dist/style.min.css", @@ -34,5 +34,5 @@ "publishConfig": { "access": "public" }, - "stableVersion": "2.1.1" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/status-bar/package.json b/packages/@uppy/status-bar/package.json index 9dc073ec8c..ec94264496 100644 --- a/packages/@uppy/status-bar/package.json +++ b/packages/@uppy/status-bar/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/status-bar", "description": "A progress bar for Uppy, with many bells and whistles.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "style": "dist/style.min.css", @@ -27,7 +27,7 @@ "url": "git+https://github.com/transloadit/uppy.git" }, "dependencies": { - "@transloadit/prettier-bytes": "0.0.7", + "@transloadit/prettier-bytes": "0.0.9", "@uppy/utils": "workspace:^", "classnames": "^2.2.6", "lodash.throttle": "^4.1.1", @@ -36,5 +36,5 @@ "peerDependencies": { "@uppy/core": "workspace:^" }, - "stableVersion": "2.2.1" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/store-default/package.json b/packages/@uppy/store-default/package.json index fb0838c186..5ceb03004e 100644 --- a/packages/@uppy/store-default/package.json +++ b/packages/@uppy/store-default/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/store-default", "description": "The default simple object-based store for Uppy.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -22,5 +22,5 @@ "type": "git", "url": "git+https://github.com/transloadit/uppy.git" }, - "stableVersion": "2.1.0" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/store-redux/package.json b/packages/@uppy/store-redux/package.json index 5b9aa45f32..a302882d37 100644 --- a/packages/@uppy/store-redux/package.json +++ b/packages/@uppy/store-redux/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/store-redux", "description": "Make Uppy use your existing Redux store.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -24,8 +24,8 @@ "nanoid": "^4.0.0" }, "devDependencies": { - "@jest/globals": "^27.4.2", - "redux": "4.0.5" + "@jest/globals": "^28.0.0", + "redux": "^4.0.0" }, - "stableVersion": "2.1.0" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/store-redux/types/index.test-d.ts b/packages/@uppy/store-redux/types/index.test-d.ts index cf9918498b..352c236753 100644 --- a/packages/@uppy/store-redux/types/index.test-d.ts +++ b/packages/@uppy/store-redux/types/index.test-d.ts @@ -1,5 +1,6 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { createStore, combineReducers } from 'redux' +// eslint-disable-next-line import/no-named-as-default import ReduxStore, { reducer as uppy } from '..' const reducer = combineReducers({ uppy }) diff --git a/packages/@uppy/svelte/package.json b/packages/@uppy/svelte/package.json index 7d9d110684..66daf4721e 100644 --- a/packages/@uppy/svelte/package.json +++ b/packages/@uppy/svelte/package.json @@ -3,7 +3,7 @@ "svelte": "src/index.js", "module": "dist/index.mjs", "main": "dist/index.js", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.2", "scripts": { "build": "rollup -c", "prepublishOnly": "yarn run build", @@ -16,12 +16,12 @@ "@uppy/status-bar": "workspace:^" }, "devDependencies": { - "@rollup/plugin-node-resolve": "^11.0.1", - "@tsconfig/svelte": "^1.0.10", + "@rollup/plugin-node-resolve": "^13.0.0", + "@tsconfig/svelte": "^3.0.0", "rollup": "^2.60.2", "rollup-plugin-svelte": "^7.0.0", "svelte": "^3.31.0", - "svelte-check": "^1.6.0", + "svelte-check": "^2.0.0", "svelte-preprocess": "^4.6.1" }, "peerDependencies": { @@ -38,5 +38,5 @@ "src", "dist" ], - "stableVersion": "1.0.8" + "stableVersion": "2.0.0-beta.1" } diff --git a/packages/@uppy/thumbnail-generator/package.json b/packages/@uppy/thumbnail-generator/package.json index bfad4041f7..fcecea4aa1 100644 --- a/packages/@uppy/thumbnail-generator/package.json +++ b/packages/@uppy/thumbnail-generator/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/thumbnail-generator", "description": "Uppy plugin that generates small previews of images to show on your upload UI.", - "version": "3.0.0-beta.1", + "version": "3.0.0-beta.2", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -27,11 +27,11 @@ "exifr": "^7.0.0" }, "devDependencies": { - "@jest/globals": "^27.4.2", + "@jest/globals": "^28.0.0", "namespace-emitter": "2.0.1" }, "peerDependencies": { "@uppy/core": "workspace:^" }, - "stableVersion": "2.2.0" + "stableVersion": "3.0.0-beta.1" } diff --git a/packages/@uppy/transloadit/package.json b/packages/@uppy/transloadit/package.json index 7ce1d13b5c..b2d0331b02 100644 --- a/packages/@uppy/transloadit/package.json +++ b/packages/@uppy/transloadit/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/transloadit", "description": "The Transloadit plugin can be used to upload files to Transloadit for all kinds of processing, such as transcoding video, resizing images, zipping/unzipping, and more", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -39,8 +39,8 @@ "@uppy/core": "workspace:^" }, "devDependencies": { - "@jest/globals": "^27.4.2", + "@jest/globals": "^28.0.0", "whatwg-fetch": "^3.6.2" }, - "stableVersion": "2.3.0" + "stableVersion": "3.0.0-beta.4" } diff --git a/packages/@uppy/transloadit/src/index.js b/packages/@uppy/transloadit/src/index.js index 8735a0fde3..d35bd7b1ed 100644 --- a/packages/@uppy/transloadit/src/index.js +++ b/packages/@uppy/transloadit/src/index.js @@ -1,7 +1,7 @@ import hasProperty from '@uppy/utils/lib/hasProperty' import ErrorWithCause from '@uppy/utils/lib/ErrorWithCause' import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue' -import BasePlugin from '@uppy/core/lib/BasePlugin' +import BasePlugin from '@uppy/core/lib/BasePlugin.js' import Tus from '@uppy/tus' import Assembly from './Assembly.js' import Client from './Client.js' @@ -25,9 +25,9 @@ const sendErrorToConsole = originalErr => err => { console.error(error, originalErr) } -const COMPANION = 'https://api2.transloadit.com/companion' +const COMPANION_URL = 'https://api2.transloadit.com/companion' // Regex matching acceptable postMessage() origins for authentication feedback from companion. -const ALLOWED_COMPANION_PATTERN = /\.transloadit\.com$/ +const COMPANION_ALLOWED_HOSTS = /\.transloadit\.com$/ // Regex used to check if a Companion address is run by Transloadit. const TL_COMPANION = /https?:\/\/api2(?:-\w+)?\.transloadit\.com\/companion/ @@ -37,6 +37,12 @@ const TL_COMPANION = /https?:\/\/api2(?:-\w+)?\.transloadit\.com\/companion/ export default class Transloadit extends BasePlugin { static VERSION = packageJson.version + /** @deprecated */ + static COMPANION = COMPANION_URL + + /** @deprecated */ + static COMPANION_PATTERN = COMPANION_ALLOWED_HOSTS + #rateLimitedQueue constructor (uppy, opts) { @@ -850,7 +856,6 @@ export default class Transloadit extends BasePlugin { } export { - ALLOWED_COMPANION_PATTERN, - COMPANION, - ALLOWED_COMPANION_PATTERN as COMPANION_PATTERN, + COMPANION_URL, + COMPANION_ALLOWED_HOSTS, } diff --git a/packages/@uppy/transloadit/types/index.d.ts b/packages/@uppy/transloadit/types/index.d.ts index 468b96389b..b5c2d68f2f 100644 --- a/packages/@uppy/transloadit/types/index.d.ts +++ b/packages/@uppy/transloadit/types/index.d.ts @@ -121,13 +121,16 @@ export type TransloaditOptions = TransloaditOptionsBase & } | AssemblyOptions) -declare class Transloadit extends BasePlugin { +export default class Transloadit extends BasePlugin { + /** @deprecated */ static COMPANION: string + /** @deprecated */ static COMPANION_PATTERN: RegExp } -export default Transloadit +export const COMPANION_URL: string +export const COMPANION_ALLOWED_HOSTS: RegExp // Events diff --git a/packages/@uppy/transloadit/types/index.test-d.ts b/packages/@uppy/transloadit/types/index.test-d.ts index eb05f5eae1..75fac4cdf8 100644 --- a/packages/@uppy/transloadit/types/index.test-d.ts +++ b/packages/@uppy/transloadit/types/index.test-d.ts @@ -1,10 +1,12 @@ import { expectError, expectType } from 'tsd' import Uppy from '@uppy/core' import type { UppyFile } from '@uppy/core' -import Transloadit from '..' +import Transloadit, { COMPANION_ALLOWED_HOSTS, COMPANION_URL } from '..' expectType(Transloadit.COMPANION) +expectType(COMPANION_URL) expectType(Transloadit.COMPANION_PATTERN) +expectType(COMPANION_ALLOWED_HOSTS) const validParams = { auth: { key: 'not so secret key' }, diff --git a/packages/@uppy/tus/package.json b/packages/@uppy/tus/package.json index cf9953384d..c6d7edc1ba 100644 --- a/packages/@uppy/tus/package.json +++ b/packages/@uppy/tus/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/tus", "description": "Resumable uploads for Uppy using Tus.io", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -28,8 +28,8 @@ "tus-js-client": "^3.0.0" }, "peerDependencies": { - "@jest/globals": "^27.4.2", + "@jest/globals": "^28.0.0", "@uppy/core": "workspace:^" }, - "stableVersion": "2.4.0" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/tus/src/index.js b/packages/@uppy/tus/src/index.js index 57f9c3bdfc..af0a0e76b5 100644 --- a/packages/@uppy/tus/src/index.js +++ b/packages/@uppy/tus/src/index.js @@ -1,4 +1,4 @@ -import BasePlugin from '@uppy/core/lib/BasePlugin' +import BasePlugin from '@uppy/core/lib/BasePlugin.js' import * as tus from 'tus-js-client' import { Provider, RequestClient, Socket } from '@uppy/companion-client' import emitSocketProgress from '@uppy/utils/lib/emitSocketProgress' diff --git a/packages/@uppy/unsplash/package.json b/packages/@uppy/unsplash/package.json index 8579843d11..960287dfc6 100644 --- a/packages/@uppy/unsplash/package.json +++ b/packages/@uppy/unsplash/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/unsplash", "description": "Import files from Unsplash, the free stock photography resource, into Uppy", - "version": "3.0.0-beta.1", + "version": "3.0.0-beta.2", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -32,5 +32,5 @@ "publishConfig": { "access": "public" }, - "stableVersion": "2.1.0" + "stableVersion": "3.0.0-beta.1" } diff --git a/packages/@uppy/url/package.json b/packages/@uppy/url/package.json index 1f3b28361a..651596a8e6 100644 --- a/packages/@uppy/url/package.json +++ b/packages/@uppy/url/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/url", "description": "The Url plugin lets users import files from the Internet. Paste any URL and it’ll be added!", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "style": "dist/style.min.css", @@ -30,5 +30,5 @@ "peerDependencies": { "@uppy/core": "workspace:^" }, - "stableVersion": "2.1.1" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/utils/CHANGELOG.md b/packages/@uppy/utils/CHANGELOG.md index 0ca92bd508..e4a33969f7 100644 --- a/packages/@uppy/utils/CHANGELOG.md +++ b/packages/@uppy/utils/CHANGELOG.md @@ -1,5 +1,13 @@ # @uppy/utils +## 5.0.0-beta.1 + +Released: 2022-08-16 +Included in: Uppy v3.0.0-beta.5 + +- @uppy/utils: Fix webp mimetype (Merlijn Vos / #3961) +- @uppy/utils: modernize `getDroppedFiles` (Antoine du Hamel / #3534) + ## 4.1.0 Released: 2022-05-30 diff --git a/packages/@uppy/utils/package.json b/packages/@uppy/utils/package.json index 6fa0915067..35ff2a91d6 100644 --- a/packages/@uppy/utils/package.json +++ b/packages/@uppy/utils/package.json @@ -1,9 +1,8 @@ { "name": "@uppy/utils", "description": "Shared utility functions for Uppy Core and plugins maintained by the Uppy team.", - "version": "5.0.0-beta", + "version": "5.0.0-beta.1", "license": "MIT", - "main": "lib/index.js", "types": "types/index.d.ts", "type": "module", "keywords": [ @@ -18,11 +17,55 @@ "type": "git", "url": "git+https://github.com/transloadit/uppy.git" }, + "exports": { + "./package.json": "./package.json", + "./lib/Translator": "./lib/Translator.js", + "./lib/EventTracker": "./lib/EventTracker.js", + "./lib/ProgressTimeout": "./lib/ProgressTimeout.js", + "./lib/RateLimitedQueue": "./lib/RateLimitedQueue.js", + "./lib/canvasToBlob": "./lib/canvasToBlob.js", + "./lib/dataURItoBlob": "./lib/dataURItoBlob.js", + "./lib/dataURItoFile": "./lib/dataURItoFile.js", + "./lib/emitSocketProgress": "./lib/emitSocketProgress.js", + "./lib/findAllDOMElements": "./lib/findAllDOMElements.js", + "./lib/findDOMElement": "./lib/findDOMElement.js", + "./lib/generateFileID": "./lib/generateFileID.js", + "./lib/getBytesRemaining": "./lib/getBytesRemaining.js", + "./lib/getETA": "./lib/getETA.js", + "./lib/getFileNameAndExtension": "./lib/getFileNameAndExtension.js", + "./lib/getFileType": "./lib/getFileType.js", + "./lib/getFileTypeExtension": "./lib/getFileTypeExtension.js", + "./lib/getSocketHost": "./lib/getSocketHost.js", + "./lib/getSpeed": "./lib/getSpeed.js", + "./lib/getTimeStamp": "./lib/getTimeStamp.js", + "./lib/isDOMElement": "./lib/isDOMElement.js", + "./lib/isObjectURL": "./lib/isObjectURL.js", + "./lib/isDragDropSupported": "./lib/isDragDropSupported.js", + "./lib/isPreviewSupported": "./lib/isPreviewSupported.js", + "./lib/isTouchDevice": "./lib/isTouchDevice.js", + "./lib/prettyETA": "./lib/prettyETA.js", + "./lib/secondsToTime": "./lib/secondsToTime.js", + "./lib/settle": "./lib/settle.js", + "./lib/toArray": "./lib/toArray.js", + "./lib/FOCUSABLE_ELEMENTS": "./lib/FOCUSABLE_ELEMENTS.js", + "./lib/AbortController": "./lib/AbortController.js", + "./lib/getTextDirection": "./lib/getTextDirection.js", + "./lib/NetworkError": "./lib/NetworkError.js", + "./lib/isNetworkError": "./lib/isNetworkError.js", + "./lib/truncateString": "./lib/truncateString.js", + "./lib/remoteFileObjToLocal": "./lib/remoteFileObjToLocal.js", + "./lib/fetchWithNetworkError": "./lib/fetchWithNetworkError.js", + "./lib/ErrorWithCause": "./lib/ErrorWithCause.js", + "./lib/delay": "./lib/delay.js", + "./lib/hasProperty": "./lib/hasProperty.js", + "./lib/mimeTypes": "./lib/mimeTypes.js", + "./lib/getDroppedFiles": "./lib/getDroppedFiles/index.js" + }, "dependencies": { "lodash.throttle": "^4.1.1" }, "devDependencies": { "@jest/globals": "^27.4.2" }, - "stableVersion": "4.1.0" + "stableVersion": "5.0.0-beta" } diff --git a/packages/@uppy/utils/src/getDroppedFiles/index.js b/packages/@uppy/utils/src/getDroppedFiles/index.js index 0db81b8301..8758db6ab2 100644 --- a/packages/@uppy/utils/src/getDroppedFiles/index.js +++ b/packages/@uppy/utils/src/getDroppedFiles/index.js @@ -15,11 +15,16 @@ import fallbackApi from './utils/fallbackApi.js' * * @returns {Promise} - Array */ -export default function getDroppedFiles (dataTransfer, { logDropError = () => {} } = {}) { +export default async function getDroppedFiles (dataTransfer, { logDropError = () => {} } = {}) { // Get all files from all subdirs. Works (at least) in Chrome, Mozilla, and Safari - if (dataTransfer.items?.[0] && 'webkitGetAsEntry' in dataTransfer.items[0]) { - return webkitGetAsEntryApi(dataTransfer, logDropError) + try { + const accumulator = [] + for await (const file of webkitGetAsEntryApi(dataTransfer, logDropError)) { + accumulator.push(file) + } + return accumulator // Otherwise just return all first-order files + } catch { + return fallbackApi(dataTransfer) } - return fallbackApi(dataTransfer) } diff --git a/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/getFilesAndDirectoriesFromDirectory.js b/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/getFilesAndDirectoriesFromDirectory.js index 42bb15aa61..65cbc174b9 100644 --- a/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/getFilesAndDirectoriesFromDirectory.js +++ b/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/getFilesAndDirectoriesFromDirectory.js @@ -13,9 +13,9 @@ export default function getFilesAndDirectoriesFromDirectory (directoryReader, ol // According to the FileSystem API spec, getFilesAndDirectoriesFromDirectory() // must be called until it calls the onSuccess with an empty array. if (entries.length) { - setTimeout(() => { + queueMicrotask(() => { getFilesAndDirectoriesFromDirectory(directoryReader, newEntries, logDropError, { onSuccess }) - }, 0) + }) // Done iterating this particular directory } else { onSuccess(newEntries) diff --git a/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/index.js b/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/index.js index ab97e6ec9a..8db7fb029e 100644 --- a/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/index.js +++ b/packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi/index.js @@ -1,56 +1,61 @@ import getRelativePath from './getRelativePath.js' import getFilesAndDirectoriesFromDirectory from './getFilesAndDirectoriesFromDirectory.js' -import toArray from '../../../toArray.js' -export default function webkitGetAsEntryApi (dataTransfer, logDropError) { - const files = [] - - const rootPromises = [] - - /** - * Returns a resolved promise, when :files array is enhanced - * - * @param {(FileSystemFileEntry|FileSystemDirectoryEntry)} entry - * @returns {Promise} - empty promise that resolves when :files is enhanced with a file - */ - const createPromiseToAddFileOrParseDirectory = (entry) => new Promise((resolve) => { - // This is a base call - if (entry.isFile) { - // Creates a new File object which can be used to read the file. - entry.file( - (file) => { - // eslint-disable-next-line no-param-reassign - file.relativePath = getRelativePath(entry) - files.push(file) - resolve() - }, - // Make sure we resolve on error anyway, it's fine if only one file couldn't be read! - (error) => { - logDropError(error) - resolve() - }, - ) - // This is a recursive call - } else if (entry.isDirectory) { +/** + * Interop between deprecated webkitGetAsEntry and standard getAsFileSystemHandle. + */ +function getAsFileSystemHandleFromEntry (entry, logDropError) { + if (entry == null) return entry + return { + // eslint-disable-next-line no-nested-ternary + kind: entry.isFile ? 'file' : entry.isDirectory ? 'directory' : undefined, + getFile () { + return new Promise((resolve, reject) => entry.file(resolve, reject)) + }, + async* values () { + // If the file is a directory. const directoryReader = entry.createReader() - getFilesAndDirectoriesFromDirectory(directoryReader, [], logDropError, { - onSuccess: (entries) => resolve(Promise.all( - entries.map(createPromiseToAddFileOrParseDirectory), - )), + const entries = await new Promise(resolve => { + getFilesAndDirectoriesFromDirectory(directoryReader, [], logDropError, { + onSuccess: (dirEntries) => resolve(dirEntries.map(file => getAsFileSystemHandleFromEntry(file, logDropError))), + }) }) - } - }) + yield* entries + }, + } +} +async function* createPromiseToAddFileOrParseDirectory (entry) { // For each dropped item, - make sure it's a file/directory, and start deepening in! - toArray(dataTransfer.items) - .forEach((item) => { - const entry = item.webkitGetAsEntry() - // :entry can be null when we drop the url e.g. - if (entry) { - rootPromises.push(createPromiseToAddFileOrParseDirectory(entry)) - } - }) + if (entry.kind === 'file') { + const file = await entry.getFile() + if (file !== null) { + file.relativePath = getRelativePath(entry) + yield file + } + } else if (entry.kind === 'directory') { + for await (const handle of entry.values()) { + yield* createPromiseToAddFileOrParseDirectory(handle) + } + } +} - return Promise.all(rootPromises) - .then(() => files) +export default async function* getFilesFromDataTransfer (dataTransfer, logDropError) { + for (const item of dataTransfer.items) { + const lastResortFile = item.getAsFile() // Chromium bug, see https://github.com/transloadit/uppy/issues/3505. + const entry = await item.getAsFileSystemHandle?.() + ?? getAsFileSystemHandleFromEntry(item.webkitGetAsEntry(), logDropError) + // :entry can be null when we drop the url e.g. + if (entry != null) { + try { + yield* createPromiseToAddFileOrParseDirectory(entry, logDropError) + } catch (err) { + if (lastResortFile) { + yield lastResortFile + } else { + logDropError(err) + } + } + } + } } diff --git a/packages/@uppy/utils/src/getFileType.test.js b/packages/@uppy/utils/src/getFileType.test.js index 7e83976c35..cff0a8029a 100644 --- a/packages/@uppy/utils/src/getFileType.test.js +++ b/packages/@uppy/utils/src/getFileType.test.js @@ -37,6 +37,10 @@ describe('getFileType', () => { name: 'bar.dicom', data: 'sdfsfhfh329fhwihs', } + const fileWebp = { + name: 'bar.webp', + data: 'sdfsfhfh329fhwihs', + } const toUpper = (file) => ({ ...file, name: file.name.toUpperCase() }) expect(getFileType(fileMP3)).toEqual('audio/mp3') expect(getFileType(toUpper(fileMP3))).toEqual('audio/mp3') @@ -46,6 +50,8 @@ describe('getFileType', () => { expect(getFileType(toUpper(fileMKV))).toEqual('video/x-matroska') expect(getFileType(fileDicom)).toEqual('application/dicom') expect(getFileType(toUpper(fileDicom))).toEqual('application/dicom') + expect(getFileType(fileWebp)).toEqual('image/webp') + expect(getFileType(toUpper(fileWebp))).toEqual('image/webp') }) it('should fail gracefully if unable to detect', () => { diff --git a/packages/@uppy/utils/src/mimeTypes.js b/packages/@uppy/utils/src/mimeTypes.js index 5c781d15f4..ab02877b63 100644 --- a/packages/@uppy/utils/src/mimeTypes.js +++ b/packages/@uppy/utils/src/mimeTypes.js @@ -11,6 +11,7 @@ export default { svg: 'image/svg+xml', jpg: 'image/jpeg', png: 'image/png', + webp: 'image/webp', gif: 'image/gif', heic: 'image/heic', heif: 'image/heif', diff --git a/packages/@uppy/utils/types/index.d.ts b/packages/@uppy/utils/types/index.d.ts index 959d5790c0..d97faf8466 100644 --- a/packages/@uppy/utils/types/index.d.ts +++ b/packages/@uppy/utils/types/index.d.ts @@ -16,7 +16,7 @@ declare module '@uppy/utils/lib/Translator' { translateArray (key: string, options: Record): any[] } - export = Translator + export default Translator } declare module '@uppy/utils/lib/EventTracker' { @@ -36,7 +36,7 @@ declare module '@uppy/utils/lib/EventTracker' { remove (): void } - export = EventTracker + export default EventTracker } declare module '@uppy/utils/lib/ProgressTimeout' { @@ -47,7 +47,7 @@ declare module '@uppy/utils/lib/ProgressTimeout' { done (): void } - export = ProgressTimeout + export default ProgressTimeout } declare module '@uppy/utils/lib/RateLimitedQueue' { @@ -88,7 +88,7 @@ declare module '@uppy/utils/lib/canvasToBlob' { type: string, quality?: number ): Promise - export = canvasToBlob + export default canvasToBlob } declare module '@uppy/utils/lib/dataURItoBlob' { @@ -96,7 +96,7 @@ declare module '@uppy/utils/lib/dataURItoBlob' { dataURI: string, opts: { mimeType?: string; name?: string } ): Blob - export = dataURItoBlob + export default dataURItoBlob } declare module '@uppy/utils/lib/dataURItoFile' { @@ -104,11 +104,11 @@ declare module '@uppy/utils/lib/dataURItoFile' { dataURI: string, opts: { mimeType?: string; name?: string } ): File - export = dataURItoFile + export default dataURItoFile } declare module '@uppy/utils/lib/emitSocketProgress' { - import UppyUtils = require('@uppy/utils') + import type { UppyFile } from '@uppy/utils' interface ProgressData { progress: number @@ -119,26 +119,26 @@ declare module '@uppy/utils/lib/emitSocketProgress' { function emitSocketProgress ( uploader: unknown, progressData: ProgressData, - file: UppyUtils.UppyFile + file: UppyFile ): void - export = emitSocketProgress + export default emitSocketProgress } declare module '@uppy/utils/lib/findAllDOMElements' { function findAllDOMElements (element: string | HTMLElement): HTMLElement[] - export = findAllDOMElements + export default findAllDOMElements } declare module '@uppy/utils/lib/findDOMElement' { function findDOMElement (element: string | HTMLElement): HTMLElement | null - export = findDOMElement + export default findDOMElement } declare module '@uppy/utils/lib/generateFileID' { - import UppyUtils = require('@uppy/utils') + import type { UppyFile } from '@uppy/utils' - function generateFileID (file: UppyUtils.UppyFile): string - export = generateFileID + function generateFileID (file: UppyFile): string + export default generateFileID } declare module '@uppy/utils/lib/getBytesRemaining' { @@ -146,36 +146,36 @@ declare module '@uppy/utils/lib/getBytesRemaining' { bytesTotal: number bytesUploaded: number }): number - export = getBytesRemaining + export default getBytesRemaining } declare module '@uppy/utils/lib/getETA' { function getETA (progress: unknown): number - export = getETA + export default getETA } declare module '@uppy/utils/lib/getFileNameAndExtension' { function getFileNameAndExtension( filename: string ): { name: string, extension: string | undefined } - export = getFileNameAndExtension + export default getFileNameAndExtension } declare module '@uppy/utils/lib/getFileType' { - import UppyUtils = require('@uppy/utils') + import type { UppyFile } from '@uppy/utils' - function getFileType (file: UppyUtils.UppyFile): string - export = getFileType + function getFileType (file: UppyFile): string + export default getFileType } declare module '@uppy/utils/lib/getFileTypeExtension' { function getFileTypeExtension (mime: string): string - export = getFileTypeExtension + export default getFileTypeExtension } declare module '@uppy/utils/lib/getSocketHost' { function getSocketHost (url: string): string - export = getSocketHost + export default getSocketHost } declare module '@uppy/utils/lib/getSpeed' { @@ -183,59 +183,65 @@ declare module '@uppy/utils/lib/getSpeed' { bytesTotal: number bytesUploaded: number }): number - export = getSpeed + export default getSpeed } declare module '@uppy/utils/lib/getTimeStamp' { function getTimeStamp (): string - export = getTimeStamp + export default getTimeStamp } declare module '@uppy/utils/lib/isDOMElement' { function isDOMElement (element: any): boolean - export = isDOMElement + export default isDOMElement } declare module '@uppy/utils/lib/isObjectURL' { function isObjectURL (url: string): boolean - export = isObjectURL + export default isObjectURL } declare module '@uppy/utils/lib/isDragDropSupported' { function isDragDropSupported (): boolean - export = isDragDropSupported + export default isDragDropSupported } declare module '@uppy/utils/lib/isPreviewSupported' { function isPreviewSupported (mime: string): boolean - export = isPreviewSupported + export default isPreviewSupported } declare module '@uppy/utils/lib/isTouchDevice' { function isTouchDevice (): boolean - export = isTouchDevice + export default isTouchDevice } declare module '@uppy/utils/lib/prettyETA' { function prettyETA (seconds: number): string - export = prettyETA + export default prettyETA } declare module '@uppy/utils/lib/secondsToTime' { function secondsToTime (seconds: number): string - export = secondsToTime + export default secondsToTime } declare module '@uppy/utils/lib/settle' { function settle ( promises: Promise[] ): Promise<{ successful: T[]; failed: any[] }> - export = settle + export default settle } declare module '@uppy/utils/lib/toArray' { function toArray (list: any): any[] - export = toArray + export default toArray +} + +declare module '@uppy/utils/lib/AbortController' { + export const AbortController: typeof globalThis.AbortController + export const AbortSignal: typeof globalThis.AbortSignal + export function createAbortError(message?: string): DOMException } declare module '@uppy/utils/lib/getDroppedFiles' { @@ -243,7 +249,75 @@ declare module '@uppy/utils/lib/getDroppedFiles' { dataTransfer: DataTransfer, options?: Record ): Promise - export = getDroppedFiles + export default getDroppedFiles +} + +declare module '@uppy/utils/lib/getTextDirection' { + function getTextDirection (element: Node): string|undefined + export default getTextDirection +} + +declare module '@uppy/utils/lib/isNetworkError' { + export default function isNetworkError (xhr: any): boolean + +} + +declare module '@uppy/utils/lib/NetworkError' { + class NetworkError extends Error { + readonly cause: any + + readonly isNetworkError: true + + readonly request?: XMLHttpRequest + + constructor (error: any, xhr?: XMLHttpRequest) + } + + export default NetworkError +} + +declare module '@uppy/utils/lib/FOCUSABLE_ELEMENTS' { + const exports: string[] + export default exports +} + +declare module '@uppy/utils/lib/truncateString' { + export default function truncateString (string: string, maxLength: number): string +} + +declare module '@uppy/utils/lib/remoteFileObjToLocal' { + export default function remoteFileObjToLocal (file: object): Record +} + +declare module '@uppy/utils/lib/fetchWithNetworkError' { + export default function fetchWithNetworkError (...options: unknown[]): Promise +} + +declare module '@uppy/utils/lib/ErrorWithCause' { + interface ErrorOptions { + cause?: unknown; + } + + export default class ErrorWithCause extends Error { + cause: any + + isNetworkError?: true + + constructor (message: string, options?: ErrorOptions) + } +} + +declare module '@uppy/utils/lib/delay' { + export default function delay (ms:number, opts?: {signal: AbortSignal}): Promise +} + +declare module '@uppy/utils/lib/hasProperty' { + export default function has (object: any, key: string): boolean +} + +declare module '@uppy/utils/lib/mimeTypes' { + const exports: Record + export default exports } declare module '@uppy/utils' { diff --git a/packages/@uppy/vue/package.json b/packages/@uppy/vue/package.json index 0273ea1661..45fd7add8d 100644 --- a/packages/@uppy/vue/package.json +++ b/packages/@uppy/vue/package.json @@ -1,6 +1,6 @@ { "name": "@uppy/vue", - "version": "1.0.0-beta.1", + "version": "1.0.0-beta.2", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -22,5 +22,5 @@ "publishConfig": { "access": "public" }, - "stableVersion": "0.4.8" + "stableVersion": "1.0.0-beta.1" } diff --git a/packages/@uppy/webcam/package.json b/packages/@uppy/webcam/package.json index ef8b2c653b..acd106d102 100644 --- a/packages/@uppy/webcam/package.json +++ b/packages/@uppy/webcam/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/webcam", "description": "Uppy plugin that takes photos or records videos using the device's camera.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "style": "dist/style.min.css", @@ -37,5 +37,5 @@ "peerDependencies": { "@uppy/core": "workspace:^" }, - "stableVersion": "2.2.1" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/xhr-upload/package.json b/packages/@uppy/xhr-upload/package.json index e866fb9db5..e6f0256064 100644 --- a/packages/@uppy/xhr-upload/package.json +++ b/packages/@uppy/xhr-upload/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/xhr-upload", "description": "Plain and simple classic HTML multipart form uploads with Uppy, as well as uploads using the HTTP PUT method.", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -30,11 +30,11 @@ "nanoid": "^4.0.0" }, "devDependencies": { - "@jest/globals": "^27.4.2", + "@jest/globals": "^28.0.0", "nock": "^13.1.0" }, "peerDependencies": { "@uppy/core": "workspace:^" }, - "stableVersion": "2.1.1" + "stableVersion": "3.0.0-beta.2" } diff --git a/packages/@uppy/xhr-upload/src/index.js b/packages/@uppy/xhr-upload/src/index.js index 4e1e9d8611..ab93bc8462 100644 --- a/packages/@uppy/xhr-upload/src/index.js +++ b/packages/@uppy/xhr-upload/src/index.js @@ -1,4 +1,4 @@ -import BasePlugin from '@uppy/core/lib/BasePlugin' +import BasePlugin from '@uppy/core/lib/BasePlugin.js' import { nanoid } from 'nanoid/non-secure' import { Provider, RequestClient, Socket } from '@uppy/companion-client' import emitSocketProgress from '@uppy/utils/lib/emitSocketProgress' @@ -366,6 +366,7 @@ export default class XHRUpload extends BasePlugin { const client = new Client(this.uppy, file.remote.providerOptions) client.post(file.remote.url, { ...file.remote.body, + protocol: 'multipart', endpoint: opts.endpoint, size: file.data.size, fieldname: opts.fieldName, diff --git a/packages/@uppy/zoom/package.json b/packages/@uppy/zoom/package.json index a3aa16fc38..ad3a8e7efe 100644 --- a/packages/@uppy/zoom/package.json +++ b/packages/@uppy/zoom/package.json @@ -1,7 +1,7 @@ { "name": "@uppy/zoom", "description": "Import files from zoom, into Uppy.", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.2", "license": "MIT", "main": "lib/index.js", "types": "types/index.d.ts", @@ -32,5 +32,5 @@ "publishConfig": { "access": "public" }, - "stableVersion": "1.1.1" + "stableVersion": "2.0.0-beta.1" } diff --git a/packages/uppy/index.mjs b/packages/uppy/index.mjs index 66303203af..5d5d3085f5 100644 --- a/packages/uppy/index.mjs +++ b/packages/uppy/index.mjs @@ -1,5 +1,5 @@ // Core -export { default as Core, debugLogger } from '@uppy/core' +export { default as Uppy, debugLogger } from '@uppy/core' // Utilities export * as server from '@uppy/companion-client' @@ -50,4 +50,9 @@ export { default as GoldenRetriever } from '@uppy/golden-retriever' export { default as ReduxDevTools } from '@uppy/redux-dev-tools' export { default as ThumbnailGenerator } from '@uppy/thumbnail-generator' +// Special hack for Transloadit static exports +import Transloadit, { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit' +Transloadit.COMPANION_URL = COMPANION_URL +Transloadit.COMPANION_ALLOWED_HOSTS = COMPANION_ALLOWED_HOSTS + export const locales = {} diff --git a/packages/uppy/package.json b/packages/uppy/package.json index c4355cd6c1..b2279ce476 100644 --- a/packages/uppy/package.json +++ b/packages/uppy/package.json @@ -1,7 +1,7 @@ { "name": "uppy", "description": "Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "license": "MIT", "main": "index.mjs", "module": "index.mjs", @@ -54,6 +54,7 @@ "@uppy/progress-bar": "workspace:^", "@uppy/provider-views": "workspace:^", "@uppy/redux-dev-tools": "workspace:^", + "@uppy/remote-sources": "workspace:^", "@uppy/screen-capture": "workspace:^", "@uppy/status-bar": "workspace:^", "@uppy/store-default": "workspace:^", @@ -69,7 +70,7 @@ }, "devDependencies": { "abortcontroller-polyfill": "^1.7.3", - "core-js": "~3.19.3", + "core-js": "~3.24.0", "md-gum-polyfill": "^1.0.0", "regenerator-runtime": "0.13.9", "resize-observer-polyfill": "^1.5.1", diff --git a/private/dev/Dashboard.js b/private/dev/Dashboard.js index ba4d4041d4..c4c13ab295 100644 --- a/private/dev/Dashboard.js +++ b/private/dev/Dashboard.js @@ -87,7 +87,7 @@ export default () => { // .use(Unsplash, { target: Dashboard, companionUrl: COMPANION_URL, companionAllowedHosts }) .use(RemoteSources, { companionUrl: COMPANION_URL, - sources: ['Box', 'Dropbox', 'Facebook', 'GoogleDrive', 'Instagram', 'OneDrive', 'Unsplash', 'Url'], + sources: ['Box', 'Dropbox', 'Facebook', 'GoogleDrive', 'Instagram', 'OneDrive', 'Unsplash', 'Zoom', 'Url'], companionAllowedHosts, }) .use(Webcam, { diff --git a/private/dev/package.json b/private/dev/package.json index 8b51405bab..8617279721 100644 --- a/private/dev/package.json +++ b/private/dev/package.json @@ -11,8 +11,8 @@ }, "devDependencies": { "autoprefixer": "^10.2.6", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-logical": "^4.0.2", + "postcss-dir-pseudo-class": "^6.0.0", + "postcss-logical": "^5.0.0", "vite": "^3.0.0" }, "private": true, diff --git a/private/locale-pack/package.json b/private/locale-pack/package.json index 504e116b4d..bc95e615c8 100644 --- a/private/locale-pack/package.json +++ b/private/locale-pack/package.json @@ -9,9 +9,9 @@ "test": "yarn node test.mjs" }, "dependencies": { - "chalk": "^4.1.2", + "chalk": "^5.0.0", "dedent": "^0.7.0", - "glob": "^7.2.0", + "glob": "^8.0.0", "mdast-util-heading-range": "^3.1.0", "remark": "^14.0.1", "remark-frontmatter": "^4.0.1" diff --git a/private/release/config.js b/private/release/config.js index 21d9798166..92231642a4 100644 --- a/private/release/config.js +++ b/private/release/config.js @@ -1,4 +1,4 @@ export const REPO_OWNER = 'transloadit' export const REPO_NAME = 'uppy' -export const TARGET_BRANCH = '3.x' +export const TARGET_BRANCH = '4.x' export const STABLE_BRANCH = 'main' diff --git a/private/release/package.json b/private/release/package.json index 14e5b4463b..230d01c1af 100644 --- a/private/release/package.json +++ b/private/release/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "devDependencies": { - "globby": "^12.0.2", + "globby": "^13.0.0", "node-fetch": "^3.1.0", "prompts": "^2.4.2" }, diff --git a/website/package.json b/website/package.json index 32214f8d18..15e81d3ff5 100644 --- a/website/package.json +++ b/website/package.json @@ -14,7 +14,7 @@ "chalk": "2.4.2", "cssnano": "^5.0.6", "drag-drop": "^4.2.0", - "esbuild": "^0.14.3", + "esbuild": "^0.15.3", "esbuild-plugin-alias": "^0.2.1", "esbuild-plugin-babel": "^0.2.3", "glob": "^7.2.0", diff --git a/website/src/docs/companion.md b/website/src/docs/companion.md index 9a28fee239..f20db756d6 100644 --- a/website/src/docs/companion.md +++ b/website/src/docs/companion.md @@ -357,9 +357,9 @@ const options = { 1. **filePath(required)** - Full path to the directory to which provider files will be downloaded temporarily. -2. **secret(recommended)** - A secret string which Companion uses to generate authorization tokens. You should generate a long random string for this. +2. **uploadUrls(required)** - An allowlist (array) of strings (exact URLs) or regular expressions. Companion will only accept uploads to these URLs. This ensures that your Companion instance is only allowed to upload to your trusted servers and prevents [SSRF](https://en.wikipedia.org/wiki/Server-side_request_forgery) attacks. -3. **uploadUrls(recommended)** - An allowlist (array) of strings (exact URLs) or regular expressions. If specified, Companion will only accept uploads to these URLs. This is needed to make sure a Companion instance is only allowed to upload to your servers. **Omitting this leaves your system open to potential [SSRF](https://en.wikipedia.org/wiki/Server-side_request_forgery) attacks, and may throw an error in future `@uppy/companion` releases.** +3. **secret(recommended)** - A secret string which Companion uses to generate authorization tokens. You should generate a long random string for this. 4. **redisUrl(optional)** - URL to running Redis server. If this is set, the state of uploads would be stored temporarily. This helps for resumed uploads after a browser crash from the client. The stored upload would be sent back to the client on reconnection. @@ -574,4 +574,4 @@ See also [example code with a custom provider](https://github.com/transloadit/up ## Development -See [CONTRIBUTING.md](/.github/CONTRIBUTING.md#companion) +See [CONTRIBUTING.md](/docs/contributing.html#Companion) diff --git a/website/src/docs/index.md b/website/src/docs/index.md index f28b68a053..97e513ef3c 100644 --- a/website/src/docs/index.md +++ b/website/src/docs/index.md @@ -19,12 +19,12 @@ Here’s the simplest example html page with Uppy (it uses a CDN bundle, while w Uppy - +
    - + + ``` 2\. Add CSS to ``: ```html - + ``` 3\. Initialize at the bottom of the closing `` tag: @@ -181,5 +181,5 @@ export * from '@uppy/core' If you’re using Uppy from CDN, those polyfills are already included in the bundle, no need to include anything additionally: ```html - + ``` diff --git a/website/src/docs/locales.md b/website/src/docs/locales.md index 78d2c0bc38..7a2c46cb73 100644 --- a/website/src/docs/locales.md +++ b/website/src/docs/locales.md @@ -34,8 +34,8 @@ const uppy = new Uppy({ Add a ` - + + + - - + + ``` Please note that while you may be able to get 2.0 to work in IE11 this way, we do not officially support it anymore. diff --git a/website/src/docs/transloadit.md b/website/src/docs/transloadit.md index b100a6436d..3797ad5166 100644 --- a/website/src/docs/transloadit.md +++ b/website/src/docs/transloadit.md @@ -56,9 +56,12 @@ You can use this plugin together with Transloadit’s hosted Companion service t To do so each provider plugin must be configured with Transloadit’s Companion URLs: ```js +import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit' +import Dropbox from '@uppy/dropbox' + uppy.use(Dropbox, { - companionUrl: Transloadit.COMPANION, - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionUrl: COMPANION_URL, + companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }) ``` @@ -67,9 +70,12 @@ This will already work. Transloadit’s OAuth applications are used to authentic To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js +import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit' +import Dropbox from '@uppy/dropbox' + uppy.use(Dropbox, { - companionUrl: Transloadit.COMPANION, - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionUrl: COMPANION_URL, + companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', @@ -77,23 +83,22 @@ uppy.use(Dropbox, { }) ``` -## Properties +## Static exports -### `Transloadit.COMPANION` +### `COMPANION_URL` The main endpoint for Transloadit’s hosted companions. You can use this constant in remote provider options, like so: ```js import Dropbox from '@uppy/dropbox' -import Transloadit from '@uppy/transloadit' +import { COMPANION_URL } from '@uppy/transloadit' uppy.use(Dropbox, { - companionUrl: Transloadit.COMPANION, - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionUrl: COMPANION_URL, }) ``` -When using `Transloadit.COMPANION`, you should also configure [`companionAllowedHosts: Transloadit.COMPANION_PATTERN`](#Transloadit-COMPANION-PATTERN). +When using `COMPANION_URL`, you should also configure [`companionAllowedHosts: COMPANION_ALLOWED_HOSTS`](#COMPANION_ALLOWED_HOSTS). The value of this constant is `https://api2.transloadit.com/companion`. If you are using a custom [`service`](#service) option, you should also set a custom host option in your provider plugins, by taking a Transloadit API url and appending `/companion`: @@ -103,19 +108,18 @@ uppy.use(Dropbox, { }) ``` -### `Transloadit.COMPANION_PATTERN` +### `COMPANION_ALLOWED_HOSTS` A RegExp pattern matching Transloadit’s hosted companion endpoints. The pattern is used in remote provider `companionAllowedHosts` options, to make sure that third party authentication messages cannot be faked by an attacker’s page, but can only originate from Transloadit’s servers. -Use it whenever you use `companionUrl: Transloadit.COMPANION`, like so: +Use it whenever you use `companionUrl: COMPANION_URL`, like so: ```js import Dropbox from '@uppy/dropbox' -import Transloadit from '@uppy/transloadit' +import { COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit' uppy.use(Dropbox, { - companionUrl: Transloadit.COMPANION, - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }) ``` diff --git a/website/src/examples/dashboard/app.es6 b/website/src/examples/dashboard/app.es6 index 69432b7fdf..0c7d86b3b3 100644 --- a/website/src/examples/dashboard/app.es6 +++ b/website/src/examples/dashboard/app.es6 @@ -1,25 +1,25 @@ -const Uppy = require('@uppy/core') -const Dashboard = require('@uppy/dashboard') -const GoogleDrive = require('@uppy/google-drive') -const Dropbox = require('@uppy/dropbox') -const Instagram = require('@uppy/instagram') -const Facebook = require('@uppy/facebook') -const OneDrive = require('@uppy/onedrive') -const Zoom = require('@uppy/zoom') -const Unsplash = require('@uppy/unsplash') -const Box = require('@uppy/box') -const ImageEditor = require('@uppy/image-editor') -const Url = require('@uppy/url') -const Webcam = require('@uppy/webcam') -const Audio = require('@uppy/audio') -const ScreenCapture = require('@uppy/screen-capture') -const Tus = require('@uppy/tus') -const DropTarget = require('@uppy/drop-target') -const GoldenRetriever = require('@uppy/golden-retriever') -const Compressor = require('@uppy/compressor') -const localeList = require('../locale_list.json') - -const COMPANION = require('../env') +import Uppy, { debugLogger } from '@uppy/core' +import Dashboard from '@uppy/dashboard' +import GoogleDrive from '@uppy/google-drive' +import Dropbox from '@uppy/dropbox' +import Instagram from '@uppy/instagram' +import Facebook from '@uppy/facebook' +import OneDrive from '@uppy/onedrive' +import Zoom from '@uppy/zoom' +import Unsplash from '@uppy/unsplash' +import Box from '@uppy/box' +import ImageEditor from '@uppy/image-editor' +import Url from '@uppy/url' +import Webcam from '@uppy/webcam' +import Audio from '@uppy/audio' +import ScreenCapture from '@uppy/screen-capture' +import Tus from '@uppy/tus' +import DropTarget from '@uppy/drop-target' +import GoldenRetriever from '@uppy/golden-retriever' +import Compressor from '@uppy/compressor' +import localeList from '../locale_list.json' + +import COMPANION from '../env.js' const RTL_LOCALES = ['ar_SA', 'fa_IR', 'he_IL'] @@ -37,7 +37,7 @@ function uppyInit () { const opts = window.uppyOptions const uppy = new Uppy({ - logger: Uppy.debugLogger, + logger: debugLogger, }) uppy.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' }) @@ -242,7 +242,7 @@ function loadLocaleFromCDN (localeName) { const head = document.getElementsByTagName('head')[0] const js = document.createElement('script') js.type = 'text/javascript' - js.src = `https://releases.transloadit.com/uppy/locales/v3.0.0-beta.3/${localeName}.min.js` + js.src = `https://releases.transloadit.com/uppy/locales/v3.0.0-beta.4/${localeName}.min.js` head.appendChild(js) } diff --git a/website/src/examples/dashboard/index.ejs b/website/src/examples/dashboard/index.ejs index 5441e06923..50e46d321e 100644 --- a/website/src/examples/dashboard/index.ejs +++ b/website/src/examples/dashboard/index.ejs @@ -21,67 +21,4 @@ Dashboard is the full-featured UI for Uppy that shows nice file previews and up
    Note: in this snippet we've omitted the code to toggle options using checkboxes. The behavior of this code may be different from the above example depending on which options you've selected.
    -{% codeblock lang:js %} -const Uppy = require('@uppy/core') -const Dashboard = require('@uppy/dashboard') -const GoogleDrive = require('@uppy/google-drive') -const Dropbox = require('@uppy/dropbox') -const Unsplash = require('@uppy/unsplash') -const Box = require('@uppy/box') -const Instagram = require('@uppy/instagram') -const Facebook = require('@uppy/facebook') -const OneDrive = require('@uppy/onedrive') -const Webcam = require('@uppy/webcam') -const ScreenCapture = require('@uppy/screen-capture') -const ImageEditor = require('@uppy/image-editor') -const Tus = require('@uppy/tus') -const Url = require('@uppy/url') -const DropTarget = require('@uppy/drop-target') -const GoldenRetriever = require('@uppy/golden-retriever') -const Compressor = require('@uppy/compressor') - -const uppy = new Uppy({ - debug: true, - autoProceed: false, - restrictions: { - maxFileSize: 1000000, - maxNumberOfFiles: 3, - minNumberOfFiles: 2, - allowedFileTypes: ['image/*', 'video/*'], - requiredMetaFields: ['caption'], - } -}) -.use(Dashboard, { - trigger: '.UppyModalOpenerBtn', - inline: true, - target: '.DashboardContainer', - showProgressDetails: true, - note: 'Images and video only, 2–3 files, up to 1 MB', - height: 470, - metaFields: [ - { id: 'name', name: 'Name', placeholder: 'file name' }, - { id: 'caption', name: 'Caption', placeholder: 'describe what the image is about' } - ], - browserBackButtonClose: false -}) -.use(GoogleDrive, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Dropbox, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Box, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Instagram, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Facebook, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(OneDrive, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Unsplash, { target: Dashboard, companionUrl: 'https://companion.uppy.io' }) -.use(Webcam, { target: Dashboard }) -.use(Audio, { target: Dashboard }) -.use(ScreenCapture, { target: Dashboard }) -.use(ImageEditor, { target: Dashboard }) -.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' }) -.use(DropTarget, {target: document.body }) -.use(GoldenRetriever) -.use(Compressor) - -uppy.on('complete', result => { - console.log('successful files:', result.successful) - console.log('failed files:', result.failed) -}) -{% endcodeblock %} +{% include_code lang:js dashboard/app.es6 %} diff --git a/website/src/examples/dragdrop/app.es6 b/website/src/examples/dragdrop/app.es6 index 59b2044e2d..22871b9866 100644 --- a/website/src/examples/dragdrop/app.es6 +++ b/website/src/examples/dragdrop/app.es6 @@ -1,7 +1,7 @@ -const Uppy = require('@uppy/core') -const DragDrop = require('@uppy/drag-drop') -const ProgressBar = require('@uppy/progress-bar') -const Tus = require('@uppy/tus') +import Uppy from '@uppy/core' +import DragDrop from '@uppy/drag-drop' +import ProgressBar from '@uppy/progress-bar' +import Tus from '@uppy/tus' // Function for displaying uploaded files const onUploadSuccess = (elForUploadedFiles) => (file, response) => { diff --git a/website/src/examples/i18n/app.html b/website/src/examples/i18n/app.html index 96145233e2..028218e5b4 100644 --- a/website/src/examples/i18n/app.html +++ b/website/src/examples/i18n/app.html @@ -1,7 +1,7 @@ - +
    @@ -12,9 +12,9 @@
    Uploaded files:
    - - - + + + -const robodog = require('@uppy/robodog') +import robodog from '@uppy/robodog' const TRANSLOADIT_EXAMPLE_KEY = '35c1aed03f5011e982b6afe82599b6a0' const TRANSLOADIT_EXAMPLE_TEMPLATE = '0b2ee2bc25dc43619700c2ce0a75164a' diff --git a/website/src/examples/statusbar/app.es6 b/website/src/examples/statusbar/app.es6 index fa5c0f63b1..ff9ef996f5 100644 --- a/website/src/examples/statusbar/app.es6 +++ b/website/src/examples/statusbar/app.es6 @@ -1,7 +1,7 @@ -const Uppy = require('@uppy/core') -const FileInput = require('@uppy/file-input') -const StatusBar = require('@uppy/status-bar') -const Tus = require('@uppy/tus') +import Uppy from '@uppy/core' +import FileInput from '@uppy/file-input' +import StatusBar from '@uppy/status-bar' +import Tus from '@uppy/tus' const uppyOne = new Uppy({ debug: true, autoProceed: true }) uppyOne diff --git a/website/src/examples/transloadit/app.es6 b/website/src/examples/transloadit/app.es6 index b1eb8bcb6f..568b1d2944 100644 --- a/website/src/examples/transloadit/app.es6 +++ b/website/src/examples/transloadit/app.es6 @@ -1,11 +1,10 @@ -const Uppy = require('@uppy/core') -const Dashboard = require('@uppy/dashboard') -const Webcam = require('@uppy/webcam') -const Transloadit = require('@uppy/transloadit') -const Instagram = require('@uppy/instagram') -const Facebook = require('@uppy/facebook') -const Zoom = require('@uppy/zoom') -const COMPANION = require('../env') +import Uppy from '@uppy/core' +import Dashboard from '@uppy/dashboard' +import Webcam from '@uppy/webcam' +import Transloadit, { COMPANION_ALLOWED_HOSTS, COMPANION_URL } from '@uppy/transloadit' +import Instagram from '@uppy/instagram' +import Facebook from '@uppy/facebook' +import Zoom from '@uppy/zoom' const enc = new TextEncoder('utf-8') async function sha1 (secret, body) { @@ -125,20 +124,20 @@ function initUppy (opts = {}) { }) .use(Instagram, { target: Dashboard, - companionUrl: 'https://api2.transloadit.com/companion', - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionUrl: COMPANION_URL, + companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }) .use(Facebook, { target: Dashboard, - companionUrl: COMPANION, + companionUrl: COMPANION_URL, }) .use(Webcam, { target: Dashboard, modes: ['picture'] }) if (zoomMode) { uppy.use(Zoom, { target: Dashboard, - companionUrl: 'https://api2.transloadit.com/companion', - companionAllowedHosts: Transloadit.COMPANION_PATTERN, + companionUrl: COMPANION_URL, + companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }) } diff --git a/website/src/examples/transloadit/index.ejs b/website/src/examples/transloadit/index.ejs index dd92099c32..8575bd2ab0 100644 --- a/website/src/examples/transloadit/index.ejs +++ b/website/src/examples/transloadit/index.ejs @@ -89,80 +89,4 @@ This example demonstrates how to unlock Transloadit’s features within Uppy.

    On this page we're using the following JavaScript:

    -{% codeblock lang:js %} -const Uppy = require('@uppy/core') -const Dashboard = require('@uppy/transloadit') -const Webcam = require('@uppy/webcam') -const Transloadit = require('@uppy/transloadit') -const Instagram = require('@uppy/instagram') - -const uppy = new Uppy({ - debug: true, - autoProceed: false, - restrictions: { - maxFileSize: 1024 * 1024 * 1024, - maxNumberOfFiles: 2, - minNumberOfFiles: 1, - allowedFileTypes: ['image/*'] - }, - locale: { - strings: { - youCanOnlyUploadFileTypes: 'You can only upload images' - } - } -}) - -uppy - .use(Transloadit, { - params: { - auth: { - key: YOUR_TRANSLOADIT_API_KEY - }, - // It’s more secure to use a template_id and enable - // Signature Authentication - steps: { - resize: { - robot: '/image/resize', - width: 250, - height: 250, - resize_strategy: 'fit', - text: [ - { - text: '© Transloadit.com', - size: 12, - font: 'Ubuntu', - color: '#eeeeee', - valign: 'bottom', - align: 'right', - x_offset: 16, - y_offset: -10 - } - ] - } - } - }, - waitForEncoding: true - }) - .use(Instagram, { target: Dashboard, companionUrl: 'https://api2.transloadit.com/companion', companionAllowedHosts: /\.transloadit\.com$/ }) - .use(Dashboard, { - inline: true, - maxHeight: 400, - target: '#uppy-dashboard-container', - note: 'Images and video only, 1–2 files, up to 1 MB' - }) - .use(Webcam, { target: Dashboard }) - .on('transloadit:result', (stepName, result) => { - const file = uppy.getFile(result.localId) - var resultContainer = document.createElement('div') - resultContainer.innerHTML = ` -
    -

    Name: ${file.name}

    -
    - View -
    - ` - document - .getElementById('uppy-transloadit-result') - .appendChild(resultContainer) - }) -{% endcodeblock %} +{% include_code lang:js transloadit/app.es6 %} diff --git a/website/src/examples/xhrupload/app.es6 b/website/src/examples/xhrupload/app.es6 index fcadd07c51..b26c588e49 100644 --- a/website/src/examples/xhrupload/app.es6 +++ b/website/src/examples/xhrupload/app.es6 @@ -1,7 +1,7 @@ -const Uppy = require('@uppy/core') -const FileInput = require('@uppy/file-input') -const XHRUpload = require('@uppy/xhr-upload') -const ProgressBar = require('@uppy/progress-bar') +import Uppy from '@uppy/core' +import FileInput from '@uppy/file-input' +import XHRUpload from '@uppy/xhr-upload' +import ProgressBar from '@uppy/progress-bar' document.querySelector('.Uppy').innerHTML = '' diff --git a/website/themes/uppy/layout/index.ejs b/website/themes/uppy/layout/index.ejs index ad9487c9b9..1cc56b3073 100644 --- a/website/themes/uppy/layout/index.ejs +++ b/website/themes/uppy/layout/index.ejs @@ -187,9 +187,9 @@

    © <%- date(Date.now(), 'YYYY') %> Transloadit

    - - - + + +