ソースを参照

Merge branch 'master' into feature/react-native

Artur Paikin 6 年 前
コミット
51fd4d97aa
100 ファイル変更4397 行追加2814 行削除
  1. 248 0
      .github/CONTRIBUTING.md
  2. 5 0
      .github/ISSUE_TEMPLATE/bug_report.md
  3. 5 0
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 14 0
      .github/ISSUE_TEMPLATE/integration_help.md
  5. 2 1
      .travis.yml
  6. 97 29
      CHANGELOG.md
  7. 0 3
      CONTRIBUTING.md
  8. 33 33
      README.md
  9. 0 100
      bin/bootandkill-servers
  10. 0 0
      bin/build-bundle.js
  11. 2 2
      bin/build-css.js
  12. 0 0
      bin/companion
  13. 0 42
      bin/gzip.js
  14. 1 1
      bin/release
  15. 1 0
      bin/travis-deploy
  16. 1 1
      bin/upload-to-cdn.sh
  17. 17 13
      bin/web-deploy
  18. 453 257
      examples/aws-companion/package-lock.json
  19. 6 6
      examples/aws-companion/package.json
  20. 149 81
      examples/aws-presigned-url/package-lock.json
  21. 1 1
      examples/aws-presigned-url/package.json
  22. 40 11
      examples/bundled/package-lock.json
  23. 7 6
      examples/bundled/package.json
  24. 2 2
      examples/cdn-example/index.html
  25. 26 2
      examples/dev/index.html
  26. 4 1
      examples/dev/main.js
  27. 1 1
      examples/dev/package.json
  28. 459 150
      examples/digitalocean-spaces/package-lock.json
  29. 2 2
      examples/digitalocean-spaces/package.json
  30. 479 142
      examples/multiple-instances/package-lock.json
  31. 1 1
      examples/multiple-instances/package.json
  32. 456 146
      examples/react-example/package-lock.json
  33. 1 1
      examples/react-example/package.json
  34. 457 147
      examples/redux/package-lock.json
  35. 4 4
      examples/redux/package.json
  36. 29 3
      examples/transloadit-textarea/index.html
  37. 22 105
      examples/transloadit-textarea/main.js
  38. 93 0
      examples/transloadit-textarea/template.json
  39. 2 2
      examples/uppy-with-companion/client/index.html
  40. 470 294
      examples/xhr-bundle/package-lock.json
  41. 5 5
      examples/xhr-bundle/package.json
  42. 0 3
      locales/README.md
  43. 0 63
      locales/cs_CZ.js
  44. 0 54
      locales/de_DE.js
  45. 0 54
      locales/en_US.js
  46. 0 54
      locales/es_ES.js
  47. 0 54
      locales/fi_FI.js
  48. 0 54
      locales/id_ID.js
  49. 0 54
      locales/it_IT.js
  50. 0 54
      locales/nb_NO.js
  51. 0 61
      locales/pl_PL.js
  52. 0 52
      locales/pt_BR.js
  53. 0 35
      locales/ru_RU.js
  54. 0 54
      locales/tr_TR.js
  55. 0 34
      locales/zh_CN.js
  56. 1 1
      netlify.toml
  57. 252 244
      package-lock.json
  58. 57 57
      package.json
  59. 1 1
      packages/@uppy/aws-s3-multipart/README.md
  60. 4 4
      packages/@uppy/aws-s3-multipart/package.json
  61. 10 19
      packages/@uppy/aws-s3-multipart/src/index.js
  62. 1 1
      packages/@uppy/aws-s3/README.md
  63. 5 5
      packages/@uppy/aws-s3/package.json
  64. 1 1
      packages/@uppy/companion-client/package.json
  65. 11 0
      packages/@uppy/companion-client/src/AuthError.js
  66. 28 19
      packages/@uppy/companion-client/src/Provider.js
  67. 72 41
      packages/@uppy/companion-client/src/RequestClient.js
  68. 21 0
      packages/@uppy/companion-client/src/tokenStorage.js
  69. 33 0
      packages/@uppy/companion/README.md
  70. 2 7
      packages/@uppy/companion/infra/kube/companion/companion-kube.yaml
  71. 1 1
      packages/@uppy/companion/package.json
  72. 11 0
      packages/@uppy/companion/src/server/Uploader.js
  73. 12 2
      packages/@uppy/companion/src/server/controllers/get.js
  74. 4 1
      packages/@uppy/companion/src/server/controllers/list.js
  75. 2 6
      packages/@uppy/companion/src/server/controllers/logout.js
  76. 1 1
      packages/@uppy/companion/src/server/controllers/send-token.js
  77. 7 2
      packages/@uppy/companion/src/server/controllers/thumbnail.js
  78. 8 0
      packages/@uppy/companion/src/server/controllers/url.js
  79. 22 2
      packages/@uppy/companion/src/server/helpers/jwt.js
  80. 1 1
      packages/@uppy/companion/src/server/helpers/utils.js
  81. 3 1
      packages/@uppy/companion/src/server/logger.js
  82. 1 1
      packages/@uppy/companion/src/server/middlewares.js
  83. 6 0
      packages/@uppy/companion/src/server/provider/drive/adapter.js
  84. 22 10
      packages/@uppy/companion/src/server/provider/drive/index.js
  85. 41 11
      packages/@uppy/companion/src/server/provider/dropbox/index.js
  86. 13 0
      packages/@uppy/companion/src/server/provider/error.js
  87. 34 9
      packages/@uppy/companion/src/server/provider/instagram/index.js
  88. 1 1
      packages/@uppy/companion/src/standalone/helper.js
  89. 1 1
      packages/@uppy/companion/test/__tests__/companion.js
  90. 1 1
      packages/@uppy/core/README.md
  91. 3 3
      packages/@uppy/core/package.json
  92. 19 39
      packages/@uppy/core/src/_common.scss
  93. 7 7
      packages/@uppy/core/src/index.js
  94. 7 0
      packages/@uppy/core/src/index.test.js
  95. 1 1
      packages/@uppy/dashboard/README.md
  96. 8 8
      packages/@uppy/dashboard/package.json
  97. 4 4
      packages/@uppy/dashboard/src/components/AddFiles.js
  98. 13 8
      packages/@uppy/dashboard/src/components/Dashboard.js
  99. 1 1
      packages/@uppy/dashboard/src/components/FileCard.js
  100. 48 17
      packages/@uppy/dashboard/src/index.js

+ 248 - 0
.github/CONTRIBUTING.md

@@ -0,0 +1,248 @@
+## Uppy development
+
+Fork the repository into your own account first. See the [GitHub Help](https://help.github.com/articles/fork-a-repo/) article for instructions.
+
+After you have successfully forked the repo, clone and install the project:
+
+```bash
+git clone git@github.com:YOUR_USERNAME/uppy.git
+cd uppy
+npm install
+npm run bootstrap
+```
+
+We use lerna to manage the many plugin packages Uppy has. You should always do `npm run bootstrap` after an `npm install` to make sure lerna has installed the dependencies of each package and that the `package-lock.json` in the repository root is up to date.
+
+Our website’s examples section is also our playground, please read the [Local Previews](#Local-Previews) section to get up and running.
+
+## Tests
+
+Unit tests are using Jest and can be run with:
+
+```bash
+npm run test:unit
+```
+
+For end-to-end tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Just follow [the guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM:
+
+```bash
+npm install selenium-standalone -g
+selenium-standalone install
+```
+
+And then launch it:
+
+```bash
+selenium-standalone start
+```
+
+After you have installed and launched the selenium standalone server, run:
+
+```bash
+npm run test:endtoend:local
+```
+
+By default, `test:endtoend:local` uses Firefox. You can use a different browser, like Chrome, by passing the `-b` flag:
+
+```bash
+npm run test:endtoend:local -- -b chrome
+```
+
+> Note: The `--` is important, it tells npm that the remaining arguments should be interpreted by the script itself, not by npm.
+
+You can run in multiple browsers by passing multiple `-b` flags:
+
+```bash
+npm run test:endtoend:local -- -b chrome -b firefox
+```
+
+When trying to get a specific integration test to pass, it's not that helpful to continuously run _all_ tests. You can use the `--suite` flag to run tests from a single `./test/endtoend` folder. For example, `--suite thumbnails` will only run the tests from `./test/endtoend/thumbnails`. Of course, it can also be combined with one or more `-b` flags.
+
+```bash
+npm run test:endtoend:local -- -b chrome --suite thumbnails
+```
+
+These tests are also run automatically on Travis builds with [SauceLabs](https://saucelabs.com/) cloud service using different OSes.
+
+## Releases
+
+Before doing a release, check that the examples on the website work:
+
+```bash
+npm start
+open http://localhost:4000/examples/dashboard
+```
+
+Also check the other examples:
+
+```bash
+cd examples/EXAMPLENAME
+npm install
+npm start
+```
+
+Releases are managed by [Lerna](https://github.com/lerna/lerna/tree/2.x). We do some cleanup and compile work around releases too. Use the npm release script:
+
+```bash
+npm run release
+```
+
+If you have two factor authentication enabled on your npm account, you will need to temporarily disable it when doing an uppy release. Lerna doesn't support 2FA, and while there are workarounds, they don't reliably work for us. (In particular, using the `npm_config_otp` environment variable will fail because the token expires by the time the release script starts publishing anything.)
+
+```bash
+npm profile disable-2fa
+npm run release
+npm profile enable-2fa auth-only
+```
+
+Other things to keep in mind during release:
+
+* When doing a minor release below 1.0, or a major release >= 1.0, of the `@uppy/core` package, the peerDependency of the plugin packages needs to be updated first. Eg when updating from 0.25.5 to 0.26.0, the peerDependency of each should be `"@uppy/core": "^0.26.0"` before doing `npm run release`.
+* When publishing a new package, publish it manually first with `npm publish --access public`, since by default `@`-prefixed packages are private on NPM, and Lerna will fail.
+
+After a release, the demos on transloadit.com should also be updated. After updating, check that some things work locally:
+
+ - the demos in the demo section work (try one that uses an import robot, and one that you need to upload to)
+ - the demos on the homepage work and can import from GDrive, Insta, Dropbox
+
+If you don't have access to the transloadit.com source code ping @arturi or @goto-bus-stop and we'll pick it up. :sparkles:
+
+## Website development
+
+We keep the [uppy.io](http://uppy.io) website in `./website`, so it’s easy to keep docs and code in sync as we are still iterating at high velocity.
+
+The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexo's build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack!
+
+Even though bundled in this repo, the website is regarded as a separate project. As such, it has its own `package.json` and we aim to keep the surface where the two projects interface as small as possible. `./website/update.js` is called during website builds to inject the Uppy knowledge into the site.
+
+### Local previews
+
+It is recommended to exclude `./website/public/` from your editor if you want efficient searches.
+
+To install the required node modules, type:
+
+```bash
+npm install && cd website && npm install && cd ..
+```
+
+For local previews on http://localhost:4000, type:
+
+```bash
+npm start
+```
+
+This will watch the website, as well as Uppy, as the examples, and rebuild everything and refresh your browser as files change.
+
+Then, to work on, for instance, the XHRUpload example, you would edit the following files:
+
+```bash
+${EDITOR} src/core/Core.js \
+  src/plugins/XHRUpload.js \
+  src/plugins/Plugin.js \
+  website/src/examples/xhrupload/app.es6
+```
+
+And open <http://localhost:4000/examples/xhrupload/> in your web browser.
+
+## CSS guidelines
+
+The CSS standards followed in this project closely resemble those from [Medium's CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines.
+
+### Naming conventions
+
+This project uses naming conventions adopted from the SUIT CSS framework.
+[Read about them here](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md).
+
+To quickly summarize:
+
+#### Utilities
+
+Syntax: u-[sm-|md-|lg-]<utilityName>
+
+```css
+.u-utilityName
+.u-floatLeft
+.u-lg-col6
+```
+
+#### Components
+
+Syntax: [<namespace>-]<ComponentName>[-descendentName][--modifierName]
+
+```css
+.twt-Button /* Namespaced component */
+.MyComponent /* Components pascal cased */
+.Button--default /* Modified button style */
+.Button--large
+
+.Tweet
+.Tweet-header /* Descendents */
+.Tweet-bodyText
+
+.Accordion.is-collapsed /* State of component */
+.Accordion.is-expanded
+```
+
+### SASS
+
+This project uses SASS, with some limitations on nesting.  One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator.  For example:
+
+```sass
+/* BAD */
+.Button {
+  &--disabled {
+    ...
+  }
+}
+
+/* GOOD */
+.Button {
+  ...
+}
+
+.Button--disabled {
+  ...
+}
+```
+
+### Mobile-first responsive approach
+
+Style to the mobile breakpoint with your selectors, then use `min-width` media queries to add any styles to the tablet or desktop breakpoints.
+
+### Selector, rule ordering
+
+- All selectors are sorted alphabetically and by type.
+- HTML elements go above classes and IDs in a file.
+- Rules are sorted alphabetically.
+
+```sass
+/* BAD */
+.wrapper {
+  width: 940px;
+  margin: auto;
+}
+
+h1 {
+  color: red;
+}
+
+.article {
+  width: 100%;
+  padding: 32px;
+}
+
+/* GOOD */
+h1 {
+  color: red;
+}
+
+.article {
+  padding: 32px;
+  width: 100%;
+}
+
+.wrapper {
+  margin: auto;
+  width: 940px;
+}
+```

+ 5 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,5 @@
+---
+name: Bug report
+about: Let us know about an unexpected error, a crash, or an incorrect behavior.
+labels: Bug, Triage
+---

+ 5 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,5 @@
+---
+name: Feature request
+about: Suggest a new feature or other enhancement.
+labels: Feature, Triage
+---

+ 14 - 0
.github/ISSUE_TEMPLATE/integration_help.md

@@ -0,0 +1,14 @@
+---
+name: Integration help
+title: Please use the community forum (or paid support) instead
+about: Do you need assistance with building the Uppy client in your bundler, or running Companion on your own preferred server platform?
+labels: Not Accepted
+---
+
+Transloadit is providing Uppy free of charge. If you want you can self-host all components and never pay us a dime. There's docs and tests and your Bugs and Feature Requests are always welcome on GitHub. 
+
+There is also a different category of support that we'd like to call Integration Help: making things work for you, that are already reported working for the larger community.
+
+As much as we'd like to provide detailed integration help to each non-paying user, Uppy has reached a point where this is no longer sustainable for our small crew. We end up investing our time in a million different projects, but without money flowing back, we can't ramp up our team along with the demand, spreading our team ever thinner, eventually grinding development to a halt.
+
+This is not where we want to be, so in order to offer enthusiasts, businesses, and enterprises assistance in a sustainable way, we're providing community based integration help for free at <https://community.transloadit.com/c/uppy>, and offer business paid support via <https://uppy.io/support>.

+ 2 - 1
.travis.yml

@@ -9,12 +9,13 @@ install:
 script:
 - npm run build
 - npm run test
-- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm run test:acceptance; fi
+- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm run test:endtoend; fi
 - npm run uploadcdn
 cache:
   apt: true
   directories:
   - "~/.npm"
+  - "~/.transloadit"
 services:
 - docker
 addons:

+ 97 - 29
CHANGELOG.md

@@ -1,4 +1,4 @@
-Our combined changelog and roadmap. It contains todos as well as dones.
+-Our combined changelog and roadmap. It contains todos as well as dones.
 
 Items can be optionally be tagged tagged by GitHub owner issue if discussion
 happened / is needed.
@@ -56,6 +56,7 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] transloadit: option for StatusBar’s upload button to act as a "Start assembly" button? Useful if an assembly uses only import robots, such as /s3/import to start a batch transcoding job.
 - [ ] provider: Add Facebook, OneDrive, Box
 - [ ] provider: change ProviderViews signature to receive Provider instance in second param. ref https://github.com/transloadit/uppy/pull/743#discussion_r180106070
+- [ ] provider: add sorting, filtering, previews #254
 - [ ] core: css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop)
 - [ ] webcam: Stop recording when file size is exceeded, should be possible given how the MediaRecorder API works
 - [ ] dashboard: add option to disable uploading from local disk #657
@@ -73,67 +74,134 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] webcam: Specify the resolution of the webcam images. We should add a way to specify any custom constraints to the Webcam plugin #876
 - [ ] transloadit: consider adding option to append result link from transloadit to the link thing in the Dashboard file block #1177
 - [ ] Consider uploading image thumbnails too #1212
+- [ ] Add `directories-dropped` event #849
 - [ ] dashboard: if you specified a delete endpoint, the “remove/cancel upload” button remains after the upload and it not only removes, but also sends a request to that endpoint #1216
 - [ ] dashboard: Show upload speed too if `showProgressDetails: true`. Maybe have separate options for which things are displayed, or at least have css-classes that can be hidden with `display: none` #766
 - [ ] react: Component wrappers to manage the Uppy instance, many people initialize it in render() which does not work correctly so this could make it easier for them https://github.com/transloadit/uppy/pull/1247#issuecomment-458063951
 - [ ] core: Fire event when a restriction fails #1251
+- [ ] core: customizing metadata fields, boolean metadata; see #809, #454 and related (@arturi)
+- [ ] goldenretriever: confirmation before restore, add “ghost” files #443 #257 (@arturi)
+- [ ] test: add typescript with JSDoc (@arturi)
+- [ ] locale: investigate preact-i18n@1.2.1, or our own script to report on missing i18n strings
+- [ ] build: utilize https://github.com/jonathantneal/postcss-preset-env, maybe https://github.com/jonathantneal/postcss-normalize (@arturi)
+- [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi)
+- [ ] fix incorrectly rotated image thumbnails #472
+- [ ] dragdrop: allow customizing arrow icon https://github.com/transloadit/uppy/pull/374#issuecomment-334116208 (@arturi)
+- [ ] show thumbnails when connecting with Google Drive #1162 (@ifedapoolarewaju)
 
 ## 1.0 Goals
 
 What we need to do to release Uppy 1.0
 
-- [ ] website: big release blog post
-- [ ] website: add 2 real world demos (avatar, form elements: github-comment-style-textarea)
 - [ ] chore: hunt down all `@TODO`s and either fix, or remove, or move to github issues/changelog backlog
 - [ ] chore: remove dead code/commented blocks
-- [ ] chore: remove the not-working npm scripts
 - [ ] chore: rewrite all code based on prettier+standardjs.com
-- [ ] core: uppy should not crash or be slow for many files. Specifically: be able to drop 5 files (or 7mb) without the upload button to take 2 seconds to appear
+- [ ] locale: update the locales of languages that we know ourselves. leave rest to community
+- [ ] locale: cdn (just in folder like Robodog, will attach to global) / for module to all languages in one big `@uppy/locales`
+- [ ] feature: basic React Native support (@arturi, @ifedapoolarewaju)
+- [ ] QA: add one integration test (or add to existing test) that uses more exotic (tus) options such as `useFastRemoteRetry` or `removeFingerprintOnSuccess` https://github.com/transloadit/uppy/issues/1327 (@arturi, @ifedapoolarewaju)
 - [ ] QA: manually test in multiple browsers and mobile devices again (SauceLabs can do Android/iOS too) (@nqst)
-- [x] QA: add one integration test that uses a Provider — added Url, Google Drive/Instagram/Dropbox tests are written, but tricky to automate (@ife)
-- [ ] QA: add one integration test that uses more exotic (tus) options such as `useFastRemoteRetry` (@arturi)
-- [ ] feature: preset for Transloadit that mimics jQuery SDK, check https://github.com/transloadit/jquery-sdk docs (@goto-bus-stop)
+- [ ] website: replace transloadit example with robodog example <-- add transloadit test key with restricted usage (no need to sign up yourself to try it)
+- [ ] website: big release blog post or series
+- [ ] website: design polish
+- [ ] companion: rename `serverUrl` and `serverPattern` to `companionUrl` and `companionAllowedHosts` (@ifedapoolarewaju)
+- [ ] transloadit: add error reporting, see https://github.com/transloadit/jquery-sdk/blob/891e99b08dd8142d8d8adc0553e6511967635ad7/js/lib/Modal.js#L122-L136 (@goto-bus-stop, @arturi)
+- [ ] transloadit: should adhere cancel event and abort assembly (@arturi, @goto-bus-stop)
+- [ ] dashboard: optional alert `onbeforeunload` while upload is in progress, safeguarding from accidentaly navigating away from a page with an ongoing upload
+- [x] chore: remove the not-working npm scripts (@kvz, @arturi)
+- [x] build: (BREAKING) `npm run dev` no longer starts Companion by default, use `npm run dev:with-companion` for that (@arturi)
+- [x] core: uppy should not crash or be slow for many files. Specifically: be able to drop 5 files (or 7mb) without the upload button to take 2 seconds to appear
+- [x] uppy-server: bump minor and deprecate that on npm in favour of @uppy/companion (@arturi)
 - [x] dashboard: implement Alex and Artur’s Dashboard redesign (@arturi)
-- [ ] feature: basic React Native support (@arturi owner+ios, @ife android)
-- [x] refactoring: Make `uppy-server` module live in main Uppy repo in `./server` as a second stage todo (after Lerna is done and we're happy) (@ife)
-- [x] QA: add one integration test that uses a Webpack and React/Redux environment (e.g. via `create-react-app`) (@goto-bus-stop)
-- [x] refactoring: split uppy into small packages, Lerna.js repo? and figure out how to share styles (during work, maybe add PR warning in `.github/*`? use `git mv` for everything) (@goto-bus-stop, @arturi)
-- [x] QA: make it so that all integration tests use `npm pack` and `npm install` first (@ife)
 - [x] docs: on using plugins, all options, list of plugins, i18n
 - [x] feature: beta file recovering after closed tab / browser crash
 - [x] feature: easy integration with React (UppyReact components)
 - [x] feature: finish the direct-to-s3 upload plugin and test it with the flow to then upload to :transloadit: afterwards. This is because this might influence the inner flow of the plugin architecture quite a bit
+- [x] feature: preset for Transloadit that mimics jQuery SDK, check https://github.com/transloadit/jquery-sdk docs (@goto-bus-stop)
 - [x] feature: Redux and ReduxDevTools support (currently mirrors Uppy state to Redux)
 - [x] feature: restrictions: by size, number of files, file type
+- [x] QA: add one integration test that uses a Provider — added Url, Google Drive/Instagram/Dropbox tests are written, but tricky to automate (@ife)
+- [x] QA: add one integration test that uses a Webpack and React/Redux environment (e.g. via `create-react-app`) (@goto-bus-stop)
+- [x] QA: make it so that all integration tests use `npm pack` and `npm install` first (@ife)
 - [x] QA: test uppy server. benchmarks / stress test. multiple connections, different setups, large files (10 GB)
 - [x] QA: tests for core and utils
+- [x] refactoring: Make `uppy-server` module live in main Uppy repo in `./server` as a second stage todo (after Lerna is done and we're happy) (@ife)
 - [x] refactoring: possibly switch from Yo-Yo to Preact, because it’s more stable, solves a few issues we are struggling with (onload being weird/hard/modern-browsers-only with bel; no way to pass refs to elements; extra network requests with base64 urls) and mature, “new standard”, larger community
+- [x] refactoring: split uppy into small packages, Lerna.js repo? and figure out how to share styles (during work, maybe add PR warning in `.github/*`? use `git mv` for everything) (@goto-bus-stop, @arturi)
 - [x] refactoring: webcam plugin
 - [x] uppy-server: add uppy-server to main API service to scale it horizontally. for the standalone server, we could write the script to support multiple clusters. Not sure how required or neccessary this may be for Transloadit's API service.
 - [x] uppy-server: better error handling, general cleanup (remove unused code. etc)
 - [x] uppy-server: security audit
 - [x] uppy-server: storing tokens in user’s browser only (d040281cc9a63060e2f2685c16de0091aee5c7b4)
 
-## 0.31.0
+## 0.30.3
 
-- [ ] core: customizing metadata fields, boolean metadata; see #809, #454 and related (@arturi)
-- [ ] goldenretriever: confirmation before restore, add “ghost” files #443 #257 (@arturi)
-- [ ] build: utilize https://github.com/jonathantneal/postcss-preset-env, maybe https://github.com/jonathantneal/postcss-normalize (@arturi)
-- [ ] fix incorrectly rotated image thumbnails #472
+Released: 2019-03-08
 
-# next
+| Package | Version | Package | Version |
+|-|-|-|-|
+| @uppy/aws-s3-multipart | 0.30.3 | @uppy/provider-views | 0.30.3 |
+| @uppy/aws-s3 | 0.30.3 | @uppy/react | 0.30.3 |
+| @uppy/companion-client | 0.28.3 | @uppy/redux-dev-tools | 0.30.3 |
+| @uppy/companion | 0.17.3 | @uppy/robodog | 0.30.3 |
+| @uppy/core | 0.30.3 | @uppy/status-bar | 0.30.3 |
+| @uppy/dashboard | 0.30.3 | @uppy/store-default | 0.28.3 |
+| @uppy/drag-drop | 0.30.3 | @uppy/store-redux | 0.28.3 |
+| @uppy/dropbox | 0.30.3 | @uppy/thumbnail-generator | 0.30.3 |
+| @uppy/file-input | 0.30.3 | @uppy/transloadit | 0.30.3 |
+| @uppy/form | 0.30.3 | @uppy/tus | 0.30.3 |
+| @uppy/golden-retriever | 0.30.3 | @uppy/url | 0.30.3 |
+| @uppy/google-drive | 0.30.3 | @uppy/utils | 0.30.3 |
+| @uppy/informer | 0.30.3 | @uppy/webcam | 0.30.3 |
+| @uppy/instagram | 0.30.3 | @uppy/xhr-upload | 0.30.3 |
+| @uppy/progress-bar | 0.30.3 | uppy | 0.30.3 |
+
+- @uppy/dashboard: Dashboard a11y improvements: trap focus in the active panel only (#1272 / @arturi)
+- @uppy/companion: Make providers support react native (#1286 / @ifedapoolarewaju)
+- @uppy/xhr-upload: Reject cancelled uploads (#1316 / @arturi)
+- @uppy/aws-s3: Avoid throwing error when file has been removed (#1318 / @craigjennings11)
+- @uppy/companion: Remove resources requirements for companion (#1311 / @kiloreux)
+- @uppy/webcam: Don’t show Smile! if countdown is false (#1324 / @arturi)
+- docs: update webpack homepage URLs, update Robodog readme (#1323 / @goto-bus-stop)
+
+## 0.30.1 - 0.30.2
+
+| Package | Version | Package | Version |
+|-|-|-|-|
+| @uppy/aws-s3-multipart | 0.30.2 | @uppy/provider-views | 0.30.2 |
+| @uppy/aws-s3 | 0.30.2 | @uppy/react | 0.30.2 |
+| @uppy/companion-client | 0.28.2 | @uppy/redux-dev-tools | 0.30.2 |
+| @uppy/companion | 0.17.2 | @uppy/robodog | 0.30.2 |
+| @uppy/core | 0.30.2 | @uppy/status-bar | 0.30.2 |
+| @uppy/dashboard | 0.30.2 | @uppy/store-default | 0.28.2 |
+| @uppy/drag-drop | 0.30.2 | @uppy/store-redux | 0.28.2 |
+| @uppy/dropbox | 0.30.2 | @uppy/thumbnail-generator | 0.30.2 |
+| @uppy/file-input | 0.30.2 | @uppy/transloadit | 0.30.2 |
+| @uppy/form | 0.30.2 | @uppy/tus | 0.30.2 |
+| @uppy/golden-retriever | 0.30.2 | @uppy/url | 0.30.2 |
+| @uppy/google-drive | 0.30.2 | @uppy/utils | 0.30.2 |
+| @uppy/informer | 0.30.2 | @uppy/webcam | 0.30.2 |
+| @uppy/instagram | 0.30.2 | @uppy/xhr-upload | 0.30.2 |
+| @uppy/progress-bar | 0.30.2 | uppy | 0.30.2 |
+
+- @uppy/robodog: Add Robodog to CDN (#1304 / @kvz, @arturi)
 
 ## 0.30.0
 
-- [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi)
-- [ ] test: add typescript with JSDoc (@arturi)
-- [ ] dragdrop: allow customizing arrow icon https://github.com/transloadit/uppy/pull/374#issuecomment-334116208 (@arturi)
-- [ ] dashboard: cancel button for transloadit assemblies (@arturi, @goto-bus-stop)
-- [ ] dashboard: optional alert `onbeforeunload` while upload is in progress, safeguarding from accidentaly navigating away from a page with an ongoing upload
-- [ ] transloadit: add error reporting, see https://github.com/transloadit/jquery-sdk/blob/891e99b08dd8142d8d8adc0553e6511967635ad7/js/lib/Modal.js#L122-L136 (@goto-bus-stop, @arturi)
-- [ ] server: bump minor and deprecate that on npm in favour of @uppy/companion (@ifedapoolarewaju)
-- [ ] companion: rename `serverUrl` and `serverPattern` to `companionUrl` and `companionAllowedHosts` (@ifedapoolarewaju)
-- [ ] show thumbnails when connecting with Google Drive #1162
+- @uppy/robodog: 📣⚠️Add Robodog — Transloadit browser SDK (#1135 / @goto-bus-stop)
+- @uppy/core: Set response in Core rather than in upload plugins (#1138 / @arturi)
+- @uppy/core: Don’t emit a complete event if an upload has been canceled (#1271 / @arturi)
+- @uppy/companion: Support redis option (auth_pass, etc...) (#1215 / @tranvansang)
+- @uppy/companion: sanitize text before adding to html (f77a102 / @ifedapoolarewaju)
+- @uppy/dashboard: Update pause-resume-cancel icons (#1241 / @arturi, @nqst)
+- @uppy/dashboard: Fix issues with multiple modals (#1258 / @goto-bus-stop, @arturi)
+- @uppy/dashboard: Dashboard ui fixes: fix icon animation jiggling, inherit font, allow overriding outline, fix breadcrumbs, bug with x button being stuck, fix an issue with long note margin on mobile (#1279 / @arturi)
+- @uppy/provider-views: update instagram nextPagePath after every fetch  (25e31e5 / @ifedapoolarewaju)
+- @uppy/react: Allow changing instance in `uppy` prop (#1247 / @goto-bus-stop)
+- @uppy/react: Typescript: Make DashboardModal.target prop optional (#1254 / @mattes3)
+- @uppy/aws-s3: Use user provided filename / type for uploaded object, fixes #1238 (#1257 / @goto-bus-stop)
+- @uppy/tus: Update to tus-js-client@1.6.0 with React Native support (#1250 / @arturi)
+- build: Improve dev npm script: Use Parcel for bundled example, re-build lib automatically, don’t open browser and no ghosts mode, start companion when developing (but there’s optional npm run dev:no-companion) (#1280 / @arturi)
 
 ## 0.29.1
 
@@ -228,7 +296,7 @@ What we need to do to release Uppy 1.0
 - @uppy/core: bring back i18n locale packs (#1114 / @goto-bus-stop, @arturi)
 - @uppy/companion: option validation (can use https://npm.im/ajv + JSON schema)
 - @uppy/companion: Remove duplicate typescript dependency (#1119 / @goto-bus-stop)
-- @uppy/companion: ⚠️ **breaking** Migrate provider adapter to Companion: saves 5KB on the frontend, all heavy lifting moved to the server side (#1093 / @ifedapoolarewaju) 
+- @uppy/companion: ⚠️ **breaking** Migrate provider adapter to Companion: saves 5KB on the frontend, all heavy lifting moved to the server side (#1093 / @ifedapoolarewaju)
 - @uppy/core: single-use Uppy instance: adds an `allowMultipleUploads` option to @uppy/core. If set to false, uppy.upload() can only be called once. Afterward, no new files can be added and no new uploads can be started. This is intended to serve the `<form>`-like use case. (#1064 / @goto-bus-stop)
 - @uppy/dashboard: Auto close after finish using `closeAfterFinish: true` (#1106 / @goto-bus-stop)
 - @uppy/dashboard: call `hideAllPanels` after a file is added in Dashboard, instead of `toggleAddFilesPanel(false)` that didn’t hide some panels

+ 0 - 3
CONTRIBUTING.md

@@ -1,3 +0,0 @@
-Please refer to our:
-
-- Contributor's guide in [`website/src/docs/contributing.md`](https://github.com/transloadit/uppy/blob/master/website/src/docs/contributing.md)

+ 33 - 33
README.md

@@ -63,9 +63,9 @@ const uppy = Uppy({ autoProceed: false })
 $ npm install @uppy/core @uppy/dashboard @uppy/tus
 ```
 
-We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
+We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
-Add CSS [uppy.min.css](https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.css), either to `<head>` of your HTML page or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
+Add CSS [uppy.min.css](https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.css), either to `<head>` of your HTML page or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
 
 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.
 
@@ -73,10 +73,10 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 
 ```html
 <!-- 1. Add CSS to `<head>` -->
-<link href="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.css" rel="stylesheet">
+<link href="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.css" rel="stylesheet">
 
 <!-- 2. Add JS before the closing `</body>` -->
-<script src="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.js"></script>
 
 <!-- 3. Initialize -->
 <div class="UppyDragDrop"></div>
@@ -163,7 +163,7 @@ If you're using Uppy via a script tag, you can load the polyfills from [JSDelivr
 ```html
 <script src="https://cdn.jsdelivr.net/npm/es6-promise@4.2.5/dist/es6-promise.auto.min.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/whatwg-fetch@3.0.0/dist/fetch.umd.min.js"></script>
-<script src="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.js"></script>
 ```
 
 ## FAQ
@@ -208,7 +208,7 @@ And you’ll need [`@uppy/companion`](https://uppy.io/docs/companion) if you’d
 
 ## Contributions are welcome
 
- - Contributor’s guide in [`website/src/docs/contributing.md`](website/src/docs/contributing.md)
+ - Contributor’s guide in [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md)
  - Changelog to track our release progress (we aim to roll out a release every month): [`CHANGELOG.md`](CHANGELOG.md)
 
 ## Used by
@@ -228,61 +228,61 @@ Use Uppy in your project? [Let us know](https://github.com/transloadit/uppy/issu
 :---: |:---: |:---: |:---: |:---: |:---: |
 [kiloreux](https://github.com/kiloreux) |[sadovnychyi](https://github.com/sadovnychyi) |[richardwillars](https://github.com/richardwillars) |[zcallan](https://github.com/zcallan) |[wilkoklak](https://github.com/wilkoklak) |[oliverpool](https://github.com/oliverpool) |
 
-[<img alt="nqst" src="https://avatars0.githubusercontent.com/u/375537?v=4&s=117" width="117">](https://github.com/nqst) |[<img alt="mattes3" src="https://avatars2.githubusercontent.com/u/2496674?v=4&s=117" width="117">](https://github.com/mattes3) |[<img alt="janko" src="https://avatars2.githubusercontent.com/u/795488?v=4&s=117" width="117">](https://github.com/janko) |[<img alt="DJWassink" src="https://avatars3.githubusercontent.com/u/1822404?v=4&s=117" width="117">](https://github.com/DJWassink) |[<img alt="taoqf" src="https://avatars3.githubusercontent.com/u/15901911?v=4&s=117" width="117">](https://github.com/taoqf) |[<img alt="bertho-zero" src="https://avatars0.githubusercontent.com/u/8525267?v=4&s=117" width="117">](https://github.com/bertho-zero) |
+[<img alt="nqst" src="https://avatars0.githubusercontent.com/u/375537?v=4&s=117" width="117">](https://github.com/nqst) |[<img alt="janko" src="https://avatars2.githubusercontent.com/u/795488?v=4&s=117" width="117">](https://github.com/janko) |[<img alt="mattes3" src="https://avatars2.githubusercontent.com/u/2496674?v=4&s=117" width="117">](https://github.com/mattes3) |[<img alt="DJWassink" src="https://avatars3.githubusercontent.com/u/1822404?v=4&s=117" width="117">](https://github.com/DJWassink) |[<img alt="taoqf" src="https://avatars3.githubusercontent.com/u/15901911?v=4&s=117" width="117">](https://github.com/taoqf) |[<img alt="gavboulton" src="https://avatars0.githubusercontent.com/u/3900826?v=4&s=117" width="117">](https://github.com/gavboulton) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[nqst](https://github.com/nqst) |[mattes3](https://github.com/mattes3) |[janko](https://github.com/janko) |[DJWassink](https://github.com/DJWassink) |[taoqf](https://github.com/taoqf) |[bertho-zero](https://github.com/bertho-zero) |
+[nqst](https://github.com/nqst) |[janko](https://github.com/janko) |[mattes3](https://github.com/mattes3) |[DJWassink](https://github.com/DJWassink) |[taoqf](https://github.com/taoqf) |[gavboulton](https://github.com/gavboulton) |
 
-[<img alt="tranvansang" src="https://avatars1.githubusercontent.com/u/13043196?v=4&s=117" width="117">](https://github.com/tranvansang) |[<img alt="frederikhors" src="https://avatars3.githubusercontent.com/u/41120635?v=4&s=117" width="117">](https://github.com/frederikhors) |[<img alt="pauln" src="https://avatars3.githubusercontent.com/u/574359?v=4&s=117" width="117">](https://github.com/pauln) |[<img alt="toadkicker" src="https://avatars1.githubusercontent.com/u/523330?v=4&s=117" width="117">](https://github.com/toadkicker) |[<img alt="gavboulton" src="https://avatars0.githubusercontent.com/u/3900826?v=4&s=117" width="117">](https://github.com/gavboulton) |[<img alt="ogtfaber" src="https://avatars2.githubusercontent.com/u/320955?v=4&s=117" width="117">](https://github.com/ogtfaber) |
+[<img alt="bertho-zero" src="https://avatars0.githubusercontent.com/u/8525267?v=4&s=117" width="117">](https://github.com/bertho-zero) |[<img alt="tranvansang" src="https://avatars1.githubusercontent.com/u/13043196?v=4&s=117" width="117">](https://github.com/tranvansang) |[<img alt="pauln" src="https://avatars3.githubusercontent.com/u/574359?v=4&s=117" width="117">](https://github.com/pauln) |[<img alt="toadkicker" src="https://avatars1.githubusercontent.com/u/523330?v=4&s=117" width="117">](https://github.com/toadkicker) |[<img alt="mrbatista" src="https://avatars0.githubusercontent.com/u/6544817?v=4&s=117" width="117">](https://github.com/mrbatista) |[<img alt="sunil-shrestha" src="https://avatars3.githubusercontent.com/u/2129058?v=4&s=117" width="117">](https://github.com/sunil-shrestha) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[tranvansang](https://github.com/tranvansang) |[frederikhors](https://github.com/frederikhors) |[pauln](https://github.com/pauln) |[toadkicker](https://github.com/toadkicker) |[gavboulton](https://github.com/gavboulton) |[ogtfaber](https://github.com/ogtfaber) |
+[bertho-zero](https://github.com/bertho-zero) |[tranvansang](https://github.com/tranvansang) |[pauln](https://github.com/pauln) |[toadkicker](https://github.com/toadkicker) |[mrbatista](https://github.com/mrbatista) |[sunil-shrestha](https://github.com/sunil-shrestha) |
 
-[<img alt="mrbatista" src="https://avatars0.githubusercontent.com/u/6544817?v=4&s=117" width="117">](https://github.com/mrbatista) |[<img alt="ap--" src="https://avatars1.githubusercontent.com/u/1463443?v=4&s=117" width="117">](https://github.com/ap--) |[<img alt="tim-kos" src="https://avatars1.githubusercontent.com/u/15005?v=4&s=117" width="117">](https://github.com/tim-kos) |[<img alt="sunil-shrestha" src="https://avatars3.githubusercontent.com/u/2129058?v=4&s=117" width="117">](https://github.com/sunil-shrestha) |[<img alt="richartkeil" src="https://avatars0.githubusercontent.com/u/8680858?v=4&s=117" width="117">](https://github.com/richartkeil) |[<img alt="Burkes" src="https://avatars2.githubusercontent.com/u/9220052?v=4&s=117" width="117">](https://github.com/Burkes) |
+[<img alt="ap--" src="https://avatars1.githubusercontent.com/u/1463443?v=4&s=117" width="117">](https://github.com/ap--) |[<img alt="tim-kos" src="https://avatars1.githubusercontent.com/u/15005?v=4&s=117" width="117">](https://github.com/tim-kos) |[<img alt="ogtfaber" src="https://avatars2.githubusercontent.com/u/320955?v=4&s=117" width="117">](https://github.com/ogtfaber) |[<img alt="btrice" src="https://avatars2.githubusercontent.com/u/4358225?v=4&s=117" width="117">](https://github.com/btrice) |[<img alt="craigjennings11" src="https://avatars2.githubusercontent.com/u/1683368?v=4&s=117" width="117">](https://github.com/craigjennings11) |[<img alt="jedwood" src="https://avatars0.githubusercontent.com/u/369060?v=4&s=117" width="117">](https://github.com/jedwood) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[mrbatista](https://github.com/mrbatista) |[ap--](https://github.com/ap--) |[tim-kos](https://github.com/tim-kos) |[sunil-shrestha](https://github.com/sunil-shrestha) |[richartkeil](https://github.com/richartkeil) |[Burkes](https://github.com/Burkes) |
+[ap--](https://github.com/ap--) |[tim-kos](https://github.com/tim-kos) |[ogtfaber](https://github.com/ogtfaber) |[btrice](https://github.com/btrice) |[craigjennings11](https://github.com/craigjennings11) |[jedwood](https://github.com/jedwood) |
 
-[<img alt="pekala" src="https://avatars1.githubusercontent.com/u/4643658?v=4&s=117" width="117">](https://github.com/pekala) |[<img alt="manuelkiessling" src="https://avatars2.githubusercontent.com/u/206592?v=4&s=117" width="117">](https://github.com/manuelkiessling) |[<img alt="Martin005" src="https://avatars0.githubusercontent.com/u/10096404?v=4&s=117" width="117">](https://github.com/Martin005) |[<img alt="btrice" src="https://avatars2.githubusercontent.com/u/4358225?v=4&s=117" width="117">](https://github.com/btrice) |[<img alt="msand" src="https://avatars2.githubusercontent.com/u/1131362?v=4&s=117" width="117">](https://github.com/msand) |[<img alt="jedwood" src="https://avatars0.githubusercontent.com/u/369060?v=4&s=117" width="117">](https://github.com/jedwood) |
+[<img alt="pekala" src="https://avatars1.githubusercontent.com/u/4643658?v=4&s=117" width="117">](https://github.com/pekala) |[<img alt="manuelkiessling" src="https://avatars2.githubusercontent.com/u/206592?v=4&s=117" width="117">](https://github.com/manuelkiessling) |[<img alt="Martin005" src="https://avatars0.githubusercontent.com/u/10096404?v=4&s=117" width="117">](https://github.com/Martin005) |[<img alt="martiuslim" src="https://avatars2.githubusercontent.com/u/17944339?v=4&s=117" width="117">](https://github.com/martiuslim) |[<img alt="Burkes" src="https://avatars2.githubusercontent.com/u/9220052?v=4&s=117" width="117">](https://github.com/Burkes) |[<img alt="richartkeil" src="https://avatars0.githubusercontent.com/u/8680858?v=4&s=117" width="117">](https://github.com/richartkeil) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[pekala](https://github.com/pekala) |[manuelkiessling](https://github.com/manuelkiessling) |[Martin005](https://github.com/Martin005) |[btrice](https://github.com/btrice) |[msand](https://github.com/msand) |[jedwood](https://github.com/jedwood) |
+[pekala](https://github.com/pekala) |[manuelkiessling](https://github.com/manuelkiessling) |[Martin005](https://github.com/Martin005) |[martiuslim](https://github.com/martiuslim) |[Burkes](https://github.com/Burkes) |[richartkeil](https://github.com/richartkeil) |
 
 [<img alt="richmeij" src="https://avatars0.githubusercontent.com/u/9741858?v=4&s=117" width="117">](https://github.com/richmeij) |[<img alt="rosenfeld" src="https://avatars1.githubusercontent.com/u/32246?v=4&s=117" width="117">](https://github.com/rosenfeld) |[<img alt="ThomasG77" src="https://avatars2.githubusercontent.com/u/642120?v=4&s=117" width="117">](https://github.com/ThomasG77) |[<img alt="zhuangya" src="https://avatars2.githubusercontent.com/u/499038?v=4&s=117" width="117">](https://github.com/zhuangya) |[<img alt="fortrieb" src="https://avatars0.githubusercontent.com/u/4126707?v=4&s=117" width="117">](https://github.com/fortrieb) |[<img alt="muhammadInam" src="https://avatars1.githubusercontent.com/u/7801708?v=4&s=117" width="117">](https://github.com/muhammadInam) |
 :---: |:---: |:---: |:---: |:---: |:---: |
 [richmeij](https://github.com/richmeij) |[rosenfeld](https://github.com/rosenfeld) |[ThomasG77](https://github.com/ThomasG77) |[zhuangya](https://github.com/zhuangya) |[fortrieb](https://github.com/fortrieb) |[muhammadInam](https://github.com/muhammadInam) |
 
-[<img alt="martiuslim" src="https://avatars2.githubusercontent.com/u/17944339?v=4&s=117" width="117">](https://github.com/martiuslim) |[<img alt="ajschmidt8" src="https://avatars0.githubusercontent.com/u/7400326?v=4&s=117" width="117">](https://github.com/ajschmidt8) |[<img alt="asmt3" src="https://avatars1.githubusercontent.com/u/1777709?v=4&s=117" width="117">](https://github.com/asmt3) |[<img alt="tuoxiansp" src="https://avatars1.githubusercontent.com/u/3960056?v=4&s=117" width="117">](https://github.com/tuoxiansp) |[<img alt="functino" src="https://avatars0.githubusercontent.com/u/415498?v=4&s=117" width="117">](https://github.com/functino) |[<img alt="radarhere" src="https://avatars2.githubusercontent.com/u/3112309?v=4&s=117" width="117">](https://github.com/radarhere) |
+[<img alt="msand" src="https://avatars2.githubusercontent.com/u/1131362?v=4&s=117" width="117">](https://github.com/msand) |[<img alt="ajschmidt8" src="https://avatars0.githubusercontent.com/u/7400326?v=4&s=117" width="117">](https://github.com/ajschmidt8) |[<img alt="asmt3" src="https://avatars1.githubusercontent.com/u/1777709?v=4&s=117" width="117">](https://github.com/asmt3) |[<img alt="amitport" src="https://avatars1.githubusercontent.com/u/1131991?v=4&s=117" width="117">](https://github.com/amitport) |[<img alt="tuoxiansp" src="https://avatars1.githubusercontent.com/u/3960056?v=4&s=117" width="117">](https://github.com/tuoxiansp) |[<img alt="radarhere" src="https://avatars2.githubusercontent.com/u/3112309?v=4&s=117" width="117">](https://github.com/radarhere) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[martiuslim](https://github.com/martiuslim) |[ajschmidt8](https://github.com/ajschmidt8) |[asmt3](https://github.com/asmt3) |[tuoxiansp](https://github.com/tuoxiansp) |[functino](https://github.com/functino) |[radarhere](https://github.com/radarhere) |
+[msand](https://github.com/msand) |[ajschmidt8](https://github.com/ajschmidt8) |[asmt3](https://github.com/asmt3) |[amitport](https://github.com/amitport) |[tuoxiansp](https://github.com/tuoxiansp) |[radarhere](https://github.com/radarhere) |
 
-[<img alt="azeemba" src="https://avatars0.githubusercontent.com/u/2160795?v=4&s=117" width="117">](https://github.com/azeemba) |[<img alt="bducharme" src="https://avatars2.githubusercontent.com/u/4173569?v=4&s=117" width="117">](https://github.com/bducharme) |[<img alt="chao" src="https://avatars2.githubusercontent.com/u/55872?v=4&s=117" width="117">](https://github.com/chao) |[<img alt="csprance" src="https://avatars0.githubusercontent.com/u/7902617?v=4&s=117" width="117">](https://github.com/csprance) |[<img alt="cbush06" src="https://avatars0.githubusercontent.com/u/15720146?v=4&s=117" width="117">](https://github.com/cbush06) |[<img alt="danmichaelo" src="https://avatars1.githubusercontent.com/u/434495?v=4&s=117" width="117">](https://github.com/danmichaelo) |
+[<img alt="bochkarev-artem" src="https://avatars2.githubusercontent.com/u/11025874?v=4&s=117" width="117">](https://github.com/bochkarev-artem) |[<img alt="azeemba" src="https://avatars0.githubusercontent.com/u/2160795?v=4&s=117" width="117">](https://github.com/azeemba) |[<img alt="bducharme" src="https://avatars2.githubusercontent.com/u/4173569?v=4&s=117" width="117">](https://github.com/bducharme) |[<img alt="chao" src="https://avatars2.githubusercontent.com/u/55872?v=4&s=117" width="117">](https://github.com/chao) |[<img alt="csprance" src="https://avatars0.githubusercontent.com/u/7902617?v=4&s=117" width="117">](https://github.com/csprance) |[<img alt="cbush06" src="https://avatars0.githubusercontent.com/u/15720146?v=4&s=117" width="117">](https://github.com/cbush06) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[azeemba](https://github.com/azeemba) |[bducharme](https://github.com/bducharme) |[chao](https://github.com/chao) |[csprance](https://github.com/csprance) |[cbush06](https://github.com/cbush06) |[danmichaelo](https://github.com/danmichaelo) |
+[bochkarev-artem](https://github.com/bochkarev-artem) |[azeemba](https://github.com/azeemba) |[bducharme](https://github.com/bducharme) |[chao](https://github.com/chao) |[csprance](https://github.com/csprance) |[cbush06](https://github.com/cbush06) |
 
-[<img alt="mrboomer" src="https://avatars0.githubusercontent.com/u/5942912?v=4&s=117" width="117">](https://github.com/mrboomer) |[<img alt="davilima6" src="https://avatars0.githubusercontent.com/u/422130?v=4&s=117" width="117">](https://github.com/davilima6) |[<img alt="yoldar" src="https://avatars3.githubusercontent.com/u/1597578?v=4&s=117" width="117">](https://github.com/yoldar) |[<img alt="lowsprofile" src="https://avatars1.githubusercontent.com/u/11029687?v=4&s=117" width="117">](https://github.com/lowsprofile) |[<img alt="FWirtz" src="https://avatars1.githubusercontent.com/u/6052785?v=4&s=117" width="117">](https://github.com/FWirtz) |[<img alt="geoffappleford" src="https://avatars2.githubusercontent.com/u/731678?v=4&s=117" width="117">](https://github.com/geoffappleford) |
+[<img alt="danmichaelo" src="https://avatars1.githubusercontent.com/u/434495?v=4&s=117" width="117">](https://github.com/danmichaelo) |[<img alt="mrboomer" src="https://avatars0.githubusercontent.com/u/5942912?v=4&s=117" width="117">](https://github.com/mrboomer) |[<img alt="davilima6" src="https://avatars0.githubusercontent.com/u/422130?v=4&s=117" width="117">](https://github.com/davilima6) |[<img alt="yoldar" src="https://avatars3.githubusercontent.com/u/1597578?v=4&s=117" width="117">](https://github.com/yoldar) |[<img alt="lowsprofile" src="https://avatars1.githubusercontent.com/u/11029687?v=4&s=117" width="117">](https://github.com/lowsprofile) |[<img alt="FWirtz" src="https://avatars1.githubusercontent.com/u/6052785?v=4&s=117" width="117">](https://github.com/FWirtz) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[mrboomer](https://github.com/mrboomer) |[davilima6](https://github.com/davilima6) |[yoldar](https://github.com/yoldar) |[lowsprofile](https://github.com/lowsprofile) |[FWirtz](https://github.com/FWirtz) |[geoffappleford](https://github.com/geoffappleford) |
+[danmichaelo](https://github.com/danmichaelo) |[mrboomer](https://github.com/mrboomer) |[davilima6](https://github.com/davilima6) |[yoldar](https://github.com/yoldar) |[lowsprofile](https://github.com/lowsprofile) |[FWirtz](https://github.com/FWirtz) |
 
-[<img alt="gjungb" src="https://avatars0.githubusercontent.com/u/3391068?v=4&s=117" width="117">](https://github.com/gjungb) |[<img alt="JacobMGEvans" src="https://avatars1.githubusercontent.com/u/27247160?v=4&s=117" width="117">](https://github.com/JacobMGEvans) |[<img alt="jcjmcclean" src="https://avatars3.githubusercontent.com/u/1822574?v=4&s=117" width="117">](https://github.com/jcjmcclean) |[<img alt="vith" src="https://avatars1.githubusercontent.com/u/3265539?v=4&s=117" width="117">](https://github.com/vith) |[<img alt="jessica-coursera" src="https://avatars1.githubusercontent.com/u/35155465?v=4&s=117" width="117">](https://github.com/jessica-coursera) |[<img alt="Dargmuesli" src="https://avatars2.githubusercontent.com/u/4778485?v=4&s=117" width="117">](https://github.com/Dargmuesli) |
+[<img alt="geoffappleford" src="https://avatars2.githubusercontent.com/u/731678?v=4&s=117" width="117">](https://github.com/geoffappleford) |[<img alt="gjungb" src="https://avatars0.githubusercontent.com/u/3391068?v=4&s=117" width="117">](https://github.com/gjungb) |[<img alt="JacobMGEvans" src="https://avatars1.githubusercontent.com/u/27247160?v=4&s=117" width="117">](https://github.com/JacobMGEvans) |[<img alt="jcjmcclean" src="https://avatars3.githubusercontent.com/u/1822574?v=4&s=117" width="117">](https://github.com/jcjmcclean) |[<img alt="vith" src="https://avatars1.githubusercontent.com/u/3265539?v=4&s=117" width="117">](https://github.com/vith) |[<img alt="jessica-coursera" src="https://avatars1.githubusercontent.com/u/35155465?v=4&s=117" width="117">](https://github.com/jessica-coursera) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[gjungb](https://github.com/gjungb) |[JacobMGEvans](https://github.com/JacobMGEvans) |[jcjmcclean](https://github.com/jcjmcclean) |[vith](https://github.com/vith) |[jessica-coursera](https://github.com/jessica-coursera) |[Dargmuesli](https://github.com/Dargmuesli) |
+[geoffappleford](https://github.com/geoffappleford) |[gjungb](https://github.com/gjungb) |[JacobMGEvans](https://github.com/JacobMGEvans) |[jcjmcclean](https://github.com/jcjmcclean) |[vith](https://github.com/vith) |[jessica-coursera](https://github.com/jessica-coursera) |
 
-[<img alt="jderrough" src="https://avatars3.githubusercontent.com/u/1108358?v=4&s=117" width="117">](https://github.com/jderrough) |[<img alt="firesharkstudios" src="https://avatars1.githubusercontent.com/u/17069637?v=4&s=117" width="117">](https://github.com/firesharkstudios) |[<img alt="kyleparisi" src="https://avatars0.githubusercontent.com/u/1286753?v=4&s=117" width="117">](https://github.com/kyleparisi) |[<img alt="dviry" src="https://avatars3.githubusercontent.com/u/1230260?v=4&s=117" width="117">](https://github.com/dviry) |[<img alt="leods92" src="https://avatars0.githubusercontent.com/u/879395?v=4&s=117" width="117">](https://github.com/leods92) |[<img alt="lucaperret" src="https://avatars1.githubusercontent.com/u/1887122?v=4&s=117" width="117">](https://github.com/lucaperret) |
+[<img alt="Dargmuesli" src="https://avatars2.githubusercontent.com/u/4778485?v=4&s=117" width="117">](https://github.com/Dargmuesli) |[<img alt="jderrough" src="https://avatars3.githubusercontent.com/u/1108358?v=4&s=117" width="117">](https://github.com/jderrough) |[<img alt="firesharkstudios" src="https://avatars1.githubusercontent.com/u/17069637?v=4&s=117" width="117">](https://github.com/firesharkstudios) |[<img alt="kyleparisi" src="https://avatars0.githubusercontent.com/u/1286753?v=4&s=117" width="117">](https://github.com/kyleparisi) |[<img alt="dviry" src="https://avatars3.githubusercontent.com/u/1230260?v=4&s=117" width="117">](https://github.com/dviry) |[<img alt="leods92" src="https://avatars0.githubusercontent.com/u/879395?v=4&s=117" width="117">](https://github.com/leods92) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[jderrough](https://github.com/jderrough) |[firesharkstudios](https://github.com/firesharkstudios) |[kyleparisi](https://github.com/kyleparisi) |[dviry](https://github.com/dviry) |[leods92](https://github.com/leods92) |[lucaperret](https://github.com/lucaperret) |
+[Dargmuesli](https://github.com/Dargmuesli) |[jderrough](https://github.com/jderrough) |[firesharkstudios](https://github.com/firesharkstudios) |[kyleparisi](https://github.com/kyleparisi) |[dviry](https://github.com/dviry) |[leods92](https://github.com/leods92) |
 
-[<img alt="mperrando" src="https://avatars2.githubusercontent.com/u/525572?v=4&s=117" width="117">](https://github.com/mperrando) |[<img alt="mnafees" src="https://avatars1.githubusercontent.com/u/1763885?v=4&s=117" width="117">](https://github.com/mnafees) |[<img alt="phillipalexander" src="https://avatars0.githubusercontent.com/u/1577682?v=4&s=117" width="117">](https://github.com/phillipalexander) |[<img alt="luarmr" src="https://avatars3.githubusercontent.com/u/817416?v=4&s=117" width="117">](https://github.com/luarmr) |[<img alt="phobos101" src="https://avatars2.githubusercontent.com/u/7114944?v=4&s=117" width="117">](https://github.com/phobos101) |[<img alt="fortunto2" src="https://avatars1.githubusercontent.com/u/1236751?v=4&s=117" width="117">](https://github.com/fortunto2) |
+[<img alt="lucaperret" src="https://avatars1.githubusercontent.com/u/1887122?v=4&s=117" width="117">](https://github.com/lucaperret) |[<img alt="mperrando" src="https://avatars2.githubusercontent.com/u/525572?v=4&s=117" width="117">](https://github.com/mperrando) |[<img alt="mnafees" src="https://avatars1.githubusercontent.com/u/1763885?v=4&s=117" width="117">](https://github.com/mnafees) |[<img alt="phillipalexander" src="https://avatars0.githubusercontent.com/u/1577682?v=4&s=117" width="117">](https://github.com/phillipalexander) |[<img alt="luarmr" src="https://avatars3.githubusercontent.com/u/817416?v=4&s=117" width="117">](https://github.com/luarmr) |[<img alt="phobos101" src="https://avatars2.githubusercontent.com/u/7114944?v=4&s=117" width="117">](https://github.com/phobos101) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[mperrando](https://github.com/mperrando) |[mnafees](https://github.com/mnafees) |[phillipalexander](https://github.com/phillipalexander) |[luarmr](https://github.com/luarmr) |[phobos101](https://github.com/phobos101) |[fortunto2](https://github.com/fortunto2) |
+[lucaperret](https://github.com/lucaperret) |[mperrando](https://github.com/mperrando) |[mnafees](https://github.com/mnafees) |[phillipalexander](https://github.com/phillipalexander) |[luarmr](https://github.com/luarmr) |[phobos101](https://github.com/phobos101) |
 
-[<img alt="sergei-zelinsky" src="https://avatars2.githubusercontent.com/u/19428086?v=4&s=117" width="117">](https://github.com/sergei-zelinsky) |[<img alt="tomsaleeba" src="https://avatars0.githubusercontent.com/u/1773838?v=4&s=117" width="117">](https://github.com/tomsaleeba) |[<img alt="vially" src="https://avatars1.githubusercontent.com/u/433598?v=4&s=117" width="117">](https://github.com/vially) |[<img alt="eltercero" src="https://avatars0.githubusercontent.com/u/545235?v=4&s=117" width="117">](https://github.com/eltercero) |[<img alt="xhocquet" src="https://avatars2.githubusercontent.com/u/8116516?v=4&s=117" width="117">](https://github.com/xhocquet) |[<img alt="avalla" src="https://avatars1.githubusercontent.com/u/986614?v=4&s=117" width="117">](https://github.com/avalla) |
+[<img alt="fortunto2" src="https://avatars1.githubusercontent.com/u/1236751?v=4&s=117" width="117">](https://github.com/fortunto2) |[<img alt="sergei-zelinsky" src="https://avatars2.githubusercontent.com/u/19428086?v=4&s=117" width="117">](https://github.com/sergei-zelinsky) |[<img alt="tomsaleeba" src="https://avatars0.githubusercontent.com/u/1773838?v=4&s=117" width="117">](https://github.com/tomsaleeba) |[<img alt="vially" src="https://avatars1.githubusercontent.com/u/433598?v=4&s=117" width="117">](https://github.com/vially) |[<img alt="eltercero" src="https://avatars0.githubusercontent.com/u/545235?v=4&s=117" width="117">](https://github.com/eltercero) |[<img alt="xhocquet" src="https://avatars2.githubusercontent.com/u/8116516?v=4&s=117" width="117">](https://github.com/xhocquet) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[sergei-zelinsky](https://github.com/sergei-zelinsky) |[tomsaleeba](https://github.com/tomsaleeba) |[vially](https://github.com/vially) |[eltercero](https://github.com/eltercero) |[xhocquet](https://github.com/xhocquet) |[avalla](https://github.com/avalla) |
+[fortunto2](https://github.com/fortunto2) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[tomsaleeba](https://github.com/tomsaleeba) |[vially](https://github.com/vially) |[eltercero](https://github.com/eltercero) |[xhocquet](https://github.com/xhocquet) |
 
-[<img alt="c0b41" src="https://avatars1.githubusercontent.com/u/2834954?v=4&s=117" width="117">](https://github.com/c0b41) |[<img alt="craigcbrunner" src="https://avatars3.githubusercontent.com/u/2780521?v=4&s=117" width="117">](https://github.com/craigcbrunner) |[<img alt="franckl" src="https://avatars0.githubusercontent.com/u/3875803?v=4&s=117" width="117">](https://github.com/franckl) |[<img alt="ninesalt" src="https://avatars2.githubusercontent.com/u/7952255?v=4&s=117" width="117">](https://github.com/ninesalt) |[<img alt="luntta" src="https://avatars0.githubusercontent.com/u/14221637?v=4&s=117" width="117">](https://github.com/luntta) |[<img alt="rhymes" src="https://avatars3.githubusercontent.com/u/146201?v=4&s=117" width="117">](https://github.com/rhymes) |
+[<img alt="avalla" src="https://avatars1.githubusercontent.com/u/986614?v=4&s=117" width="117">](https://github.com/avalla) |[<img alt="c0b41" src="https://avatars1.githubusercontent.com/u/2834954?v=4&s=117" width="117">](https://github.com/c0b41) |[<img alt="craigcbrunner" src="https://avatars3.githubusercontent.com/u/2780521?v=4&s=117" width="117">](https://github.com/craigcbrunner) |[<img alt="franckl" src="https://avatars0.githubusercontent.com/u/3875803?v=4&s=117" width="117">](https://github.com/franckl) |[<img alt="ninesalt" src="https://avatars2.githubusercontent.com/u/7952255?v=4&s=117" width="117">](https://github.com/ninesalt) |[<img alt="luntta" src="https://avatars0.githubusercontent.com/u/14221637?v=4&s=117" width="117">](https://github.com/luntta) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[c0b41](https://github.com/c0b41) |[craigcbrunner](https://github.com/craigcbrunner) |[franckl](https://github.com/franckl) |[ninesalt](https://github.com/ninesalt) |[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |
+[avalla](https://github.com/avalla) |[c0b41](https://github.com/c0b41) |[craigcbrunner](https://github.com/craigcbrunner) |[franckl](https://github.com/franckl) |[ninesalt](https://github.com/ninesalt) |[luntta](https://github.com/luntta) |
 
-[<img alt="amitport" src="https://avatars1.githubusercontent.com/u/1131991?v=4&s=117" width="117">](https://github.com/amitport) |
-:---: |
-[amitport](https://github.com/amitport) |
+[<img alt="rhymes" src="https://avatars3.githubusercontent.com/u/146201?v=4&s=117" width="117">](https://github.com/rhymes) |[<img alt="functino" src="https://avatars0.githubusercontent.com/u/415498?v=4&s=117" width="117">](https://github.com/functino) |
+:---: |:---: |
+[rhymes](https://github.com/rhymes) |[functino](https://github.com/functino) |
 <!--/contributors-->
 
 ## License

+ 0 - 100
bin/bootandkill-servers

@@ -1,100 +0,0 @@
-#!/usr/bin/env bash
-# How to run:
-#
-#  ./bootandkill-servers ./test-acceptance
-#
-# this will boot hexo & companion, run the script that you provided as an argument,
-# and tear down the servers
-
-set -o pipefail
-set -o errexit
-set -o nounset
-set -o xtrace
-
-# Set magic variables for current file & dir
-__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
-__base="$(basename ${__file} .sh)"
-__root="$(cd "$(dirname "${__dir}")" && pwd)"
-
-if [ ! -f "${__root}/env.sh" ]; then
-  cp "${__root}/env.example.sh" "${__root}/env.sh"
-fi
-if [ "${COMPANION_DROPBOX_KEY:-}" = "" ] || [ "${COMPANION_DROPBOX_KEY:-***}" = "***" ]; then
-  source "${__root}/env.sh"
-fi
-if [ "${COMPANION_DROPBOX_KEY:-}" = "" ] || [ "${COMPANION_DROPBOX_KEY:-***}" = "***" ]; then
-  echo "[${__base}] Env var COMPANION_DROPBOX_KEY still had the example value '${COMPANION_DROPBOX_KEY:-}'. "
-  echo "[${__base}] Please save the actual secrets in '${__root}/env.sh' and try again"
-  exit 1
-fi
-
-function killProcessListeningOnPort () {
-  local port="${1}"
-  lsof -n -i4TCP:${port} | awk '/LISTEN/ {print $2}' |xargs --no-run-if-empty kill -9 || true
-}
-
-function cleanup_servers () {
-  echo "[${__base}] --> Killing any server listening on port 4000"
-  killProcessListeningOnPort 4000 || true
-
-  echo "[${__base}] --> Killing any server listening on port 3020"
-  killProcessListeningOnPort 3020 || true
-
-  kill -9 ${tailPid}
-}
-
-function waitForPortOpen () {
-  local port="${1}"
-  local limit="${2:-100}"
-  local attempts=0
-  echo "[${__base}] waiting on port ${port} to open... "
-  while ! echo exit | nc localhost ${port}; do
-    let "attempts = attempts + 1"
-    echo "[${__base}] still waiting on port ${port} to open... (${attempts} / ${limit}) "
-    sleep 1
-    if [ "${attempts}" -ge "${limit}" ]; then
-      echo "[${__base}] --> Port did not open for ${limit} seconds. Aborting. "
-      exit 1
-    fi
-  done
-}
-
-echo "[${__base}] --> Killing any server listening on port 4000"
-killProcessListeningOnPort 4000 || true
-echo "[${__base}] --> Killing any server listening on port 3020"
-killProcessListeningOnPort 3020 || true
-
-echo "[${__base}] --> Start webserver and companion in the background"
-rm -f nohup.out || true
-touch nohup.out
-nohup npm run test:serve &
-tail -f nohup.out &
-tailPid=${!}
-
-trap cleanup_servers EXIT
-
-
-
-echo "[${__base}] --> Wait for hexo webserver to be online"
-waitForPortOpen 4000
-
-echo "[${__base}] --> Wait for companion to be online"
-waitForPortOpen 3020
-
-echo "[${__base}] --> Running acceptance tests"
-
-
-buildWait=20
-if [ "${TRAVIS:-}" = "true" ]; then
-  buildWait=60
-  echo "Increasing build wait because Travis has no Hexo build cache"
-fi
-
-echo "[${__base}] --> Sleeping ${buildWait}s, because the port may be open, but Hexo may still be injecting/building stuff"
-echo "[${__base}] --> and I don't know yet how to check for that"
-sleep ${buildWait}
-
-# @todo: Instead of this `sleep` we can wait until the required files are in public : )
-
-${@}

+ 0 - 0
bin/build-js.js → bin/build-bundle.js


+ 2 - 2
bin/build-css.js

@@ -2,7 +2,7 @@ const sass = require('node-sass')
 const postcss = require('postcss')
 const autoprefixer = require('autoprefixer')
 const cssnano = require('cssnano')
-const safeImportant = require('postcss-safe-important')
+// const safeImportant = require('postcss-safe-important')
 const chalk = require('chalk')
 const { promisify } = require('util')
 const fs = require('fs')
@@ -44,7 +44,7 @@ async function compileCSS () {
       }
     })
 
-    const postcssResult = await postcss([ autoprefixer, safeImportant ])
+    const postcssResult = await postcss([ autoprefixer ])
       .process(scssResult.css, { from: file })
     postcssResult.warnings().forEach(function (warn) {
       console.warn(warn.toString())

+ 0 - 0
bin/companion


+ 0 - 42
bin/gzip.js

@@ -1,42 +0,0 @@
-var path = require('path')
-var chalk = require('chalk')
-var glob = require('glob')
-var exec = require('child_process').exec
-
-function handleErr (err) {
-  console.error(chalk.red('✗ Error:'), chalk.red(err.message))
-}
-
-function gzip (file) {
-  return new Promise(function (resolve, reject) {
-    var fileName = path.basename(file)
-    var gzipCommand = 'gzip < ' + file + ' > ' + file + '.gz'
-    exec(gzipCommand, function (error, stdout, stderr) {
-      if (error) {
-        handleErr(error)
-        reject(error)
-        return
-      }
-      console.info(chalk.green('✓ Gzipped: '), chalk.magenta(fileName + '.gz'))
-      resolve()
-    })
-  })
-}
-
-function gzipDist () {
-  return new Promise(function (resolve) {
-    glob('./packages/uppy/dist/**/*.*(css|js)', function (err, files) {
-      if (err) console.log(err)
-      var gzipPromises = []
-      files.forEach(function (file) {
-        gzipPromises.push(gzip(file))
-      })
-      return Promise.all(gzipPromises).then(function () {
-        console.info(chalk.yellow('✓ Gzipped everything yo 🎉'))
-        resolve()
-      })
-    })
-  })
-}
-
-gzipDist()

+ 1 - 1
bin/release

@@ -58,7 +58,7 @@ git add README.md
 # Add readme file to the main `uppy` package.
 cp README.md packages/uppy/README.md
 
-npm run clean
+npm run build:clean
 FRESH=1 npm run build
 
 git commit --allow-empty -m "Release"

+ 1 - 0
bin/travis-deploy

@@ -8,4 +8,5 @@ git config --global user.name 'Uppy Bot'
 git config --global user.email 'uppybot@uppy.io'
 
 # because a Travis deploy script has to be a real file
+npm run web:install
 npm run web:deploy --quiet

+ 1 - 1
bin/upload-to-cdn.sh

@@ -8,7 +8,7 @@
 #  - Checks if a tag is being built (on Travis - otherwise opts to continue execution regardless)
 #  - Installs AWS CLI if needed
 #  - Assumed a fully built uppy is in root dir (unless a specific tag was specified, then it's fetched from npm)
-#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.css
+#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.css
 #  - Uses local package by default, if [version] argument was specified, takes package from npm
 #
 # Run as:

+ 17 - 13
bin/web-deploy

@@ -5,16 +5,18 @@ set -o nounset
 # set -o xtrace
 
 # Set magic variables for current file & dir
-__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
-__base="$(basename ${__file} .sh)"
+# __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# __file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
+# __base="$(basename ${__file} .sh)"
 
 ghpages_repo=${GHPAGES_REPO:-"transloadit/uppy"}
 ghpages_branch=${GHPAGES_BRANCH:-"gh-pages"}
 ghpages_url=${GHPAGES_URL:-"git@github.com:${ghpages_repo}.git"}
 
-echo "--> Deploying to GitHub pages.."
-mkdir -p /tmp/deploy-${ghpages_repo}
+localDir="${HOME:-/home/${USER:-travis}}/.${ghpages_repo}/deploy"
+
+echo "--> Deploying to GitHub pages from '${localDir}'.."
+mkdir -p "${localDir}"
 
 # Custom steps
 rsync \
@@ -28,15 +30,17 @@ rsync \
   --no-group \
   --no-motd \
   --no-owner \
-./website/public/ /tmp/deploy-${ghpages_repo} > /dev/null
+./website/public/ "${localDir}" > /dev/null
 
 echo 'This branch is just a deploy target. Do not edit. You changes will be lost.' \
-  |tee /tmp/deploy-${ghpages_repo}/README.md
+  |tee "${localDir}/README.md" > /dev/null
 
-(cd /tmp/deploy-${ghpages_repo} \
-  && git init && git checkout -B ${ghpages_branch} && git add --all . \
-  && git commit -nm "Update ${ghpages_repo} website by ${USER}" \
-  && (git remote add origin ${ghpages_url}|| true)  \
-  && git push origin ${ghpages_branch}:refs/heads/${ghpages_branch} --force) > /dev/null
+(cd "${localDir}" \
+  && ([ -d .git ] || git init) && git checkout -B "${ghpages_branch}" && (git pull origin "${ghpages_branch}" || true) && git add --all . \
+  && git commit --allow-empty --no-verify --message="Update ${ghpages_repo} website by ${USER}" \
+  && (git remote add origin "${ghpages_url}"|| true)  \
+  && (git remote set-url origin "${ghpages_url}" || true)  \
+  && (git push origin "${ghpages_branch}:refs/heads/${ghpages_branch}" || git push origin "${ghpages_branch}:refs/heads/${ghpages_branch}" --force) \
+) > /dev/null
 
-rm -rf /tmp/deploy-${ghpages_repo}
+# rm -rf "${localDir}"

ファイルの差分が大きいため隠しています
+ 453 - 257
examples/aws-companion/package-lock.json


+ 6 - 6
examples/aws-companion/package.json

@@ -17,12 +17,12 @@
     "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
     "body-parser": "^1.18.3",
-    "budo": "^11.3.2",
-    "cookie-parser": "^1.4.3",
-    "cors": "^2.8.4",
-    "express": "^4.16.3",
+    "budo": "^11.6.1",
+    "cookie-parser": "^1.4.4",
+    "cors": "^2.8.5",
+    "express": "^4.16.4",
     "express-session": "^1.15.6",
-    "npm-run-all": "^4.1.3",
-    "rimraf": "^2.6.2"
+    "npm-run-all": "^4.1.5",
+    "rimraf": "^2.6.3"
   }
 }

+ 149 - 81
examples/aws-presigned-url/package-lock.json

@@ -4,9 +4,9 @@
   "lockfileVersion": 1,
   "dependencies": {
     "JSONStream": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz",
-      "integrity": "sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg==",
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
       "dev": true,
       "requires": {
         "jsonparse": "^1.2.0",
@@ -20,33 +20,37 @@
       "dev": true
     },
     "acorn-dynamic-import": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz",
-      "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==",
-      "dev": true,
-      "requires": {
-        "acorn": "^5.0.0"
-      }
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+      "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
+      "dev": true
     },
     "acorn-node": {
-      "version": "1.5.2",
-      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.5.2.tgz",
-      "integrity": "sha512-krFKvw/d1F17AN3XZbybIUzEY4YEPNiGo05AfP3dBlfVKrMHETKpgjpuZkSF8qDNt9UkQcqj7am8yJLseklCMg==",
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz",
+      "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==",
       "dev": true,
       "requires": {
-        "acorn": "^5.7.1",
-        "acorn-dynamic-import": "^3.0.0",
+        "acorn": "^6.0.2",
+        "acorn-dynamic-import": "^4.0.0",
+        "acorn-walk": "^6.1.0",
         "xtend": "^4.0.1"
       },
       "dependencies": {
         "acorn": {
-          "version": "5.7.1",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
-          "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==",
+          "version": "6.1.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+          "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
           "dev": true
         }
       }
     },
+    "acorn-walk": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+      "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
+      "dev": true
+    },
     "aliasify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/aliasify/-/aliasify-2.1.0.tgz",
@@ -341,9 +345,9 @@
       }
     },
     "browserify": {
-      "version": "16.2.2",
-      "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.2.tgz",
-      "integrity": "sha512-fMES05wq1Oukts6ksGUU2TMVHHp06LyQt0SIwbXIHm7waSrQmNBZePsU0iM/4f94zbvb/wHma+D1YrdzWYnF/A==",
+      "version": "16.2.3",
+      "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz",
+      "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==",
       "dev": true,
       "requires": {
         "JSONStream": "^1.0.3",
@@ -397,9 +401,9 @@
       },
       "dependencies": {
         "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
+          "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
           "dev": true,
           "requires": {
             "safe-buffer": "~5.1.0"
@@ -497,9 +501,9 @@
       }
     },
     "buffer": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.0.tgz",
-      "integrity": "sha512-nUJyfChH7PMJy75eRDCCKtszSEFokUNXC1hNVSe+o+VdcgvDPLs20k3v8UXI8ruRYAJiYtyRea8mYyqPxoHWDw==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+      "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
       "dev": true,
       "requires": {
         "base64-js": "^1.0.2",
@@ -525,9 +529,9 @@
       "dev": true
     },
     "cached-path-relative": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
-      "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz",
+      "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==",
       "dev": true
     },
     "chalk": {
@@ -680,6 +684,12 @@
         "randomfill": "^1.0.3"
       }
     },
+    "dash-ast": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz",
+      "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==",
+      "dev": true
+    },
     "date-now": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
@@ -733,12 +743,12 @@
       }
     },
     "detective": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz",
-      "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==",
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
+      "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
       "dev": true,
       "requires": {
-        "acorn-node": "^1.3.0",
+        "acorn-node": "^1.6.1",
         "defined": "^1.0.0",
         "minimist": "^1.1.1"
       },
@@ -869,9 +879,9 @@
       "dev": true
     },
     "glob": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
-      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
       "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
@@ -923,9 +933,9 @@
       }
     },
     "hash.js": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz",
-      "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==",
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
       "dev": true,
       "requires": {
         "inherits": "^2.0.3",
@@ -966,9 +976,9 @@
       "dev": true
     },
     "ieee754": {
-      "version": "1.1.12",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz",
-      "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==",
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
       "dev": true
     },
     "iferr": {
@@ -1136,13 +1146,22 @@
       }
     },
     "md5.js": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
-      "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
       "dev": true,
       "requires": {
         "hash-base": "^3.0.0",
-        "inherits": "^2.0.1"
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
       }
     },
     "miller-rabin": {
@@ -1192,9 +1211,9 @@
       }
     },
     "module-deps": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.1.0.tgz",
-      "integrity": "sha512-NPs5N511VD1rrVJihSso/LiBShRbJALYBKzDW91uZYy7BpjnO4bGnZL3HjZ9yKcFdZUWwaYjDz9zxbuP7vKMuQ==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz",
+      "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==",
       "dev": true,
       "requires": {
         "JSONStream": "^1.0.3",
@@ -1260,9 +1279,9 @@
       "dev": true
     },
     "pako": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
-      "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+      "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
       "dev": true
     },
     "parents": {
@@ -1275,16 +1294,17 @@
       }
     },
     "parse-asn1": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
-      "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
+      "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==",
       "dev": true,
       "requires": {
         "asn1.js": "^4.0.0",
         "browserify-aes": "^1.0.0",
         "create-hash": "^1.1.0",
         "evp_bytestokey": "^1.0.0",
-        "pbkdf2": "^3.0.3"
+        "pbkdf2": "^3.0.3",
+        "safe-buffer": "^5.1.1"
       }
     },
     "path-browserify": {
@@ -1312,9 +1332,9 @@
       "dev": true
     },
     "pbkdf2": {
-      "version": "3.0.16",
-      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz",
-      "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==",
+      "version": "3.0.17",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+      "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
       "dev": true,
       "requires": {
         "create-hash": "^1.1.2",
@@ -1343,16 +1363,25 @@
       "dev": true
     },
     "public-encrypt": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
-      "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
       "dev": true,
       "requires": {
         "bn.js": "^4.1.0",
         "browserify-rsa": "^4.0.0",
         "create-hash": "^1.1.0",
         "parse-asn1": "^5.0.0",
-        "randombytes": "^2.0.1"
+        "randombytes": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
       }
     },
     "punycode": {
@@ -1374,9 +1403,9 @@
       "dev": true
     },
     "randombytes": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
-      "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
       "dev": true,
       "requires": {
         "safe-buffer": "^5.1.0"
@@ -1440,12 +1469,12 @@
       }
     },
     "resolve": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
-      "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
+      "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
       "dev": true,
       "requires": {
-        "path-parse": "^1.0.5"
+        "path-parse": "^1.0.6"
       }
     },
     "ripemd160": {
@@ -1524,9 +1553,9 @@
       }
     },
     "stream-browserify": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
-      "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+      "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
       "dev": true,
       "requires": {
         "inherits": "~2.0.1",
@@ -1661,13 +1690,51 @@
       "dev": true
     },
     "through2": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
-      "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
       "dev": true,
       "requires": {
-        "readable-stream": "^2.1.5",
+        "readable-stream": "~2.3.6",
         "xtend": "~4.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
       }
     },
     "timers-browserify": {
@@ -1716,12 +1783,13 @@
       "dev": true
     },
     "undeclared-identifiers": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz",
-      "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz",
+      "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==",
       "dev": true,
       "requires": {
         "acorn-node": "^1.3.0",
+        "dash-ast": "^1.0.0",
         "get-assigned-identifiers": "^1.2.0",
         "simple-concat": "^1.0.0",
         "xtend": "^4.0.1"

+ 1 - 1
examples/aws-presigned-url/package.json

@@ -8,7 +8,7 @@
     "aliasify": "^2.1.0",
     "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
-    "browserify": "^16.2.2",
+    "browserify": "^16.2.3",
     "fs-write-stream-atomic": "^1.0.10"
   }
 }

+ 40 - 11
examples/bundled/package-lock.json

@@ -904,18 +904,28 @@
       }
     },
     "@uppy/core": {
-      "version": "0.29.1",
-      "resolved": "https://registry.npmjs.org/@uppy/core/-/core-0.29.1.tgz",
-      "integrity": "sha512-k+DCWDD5SRCWqaASPDcFfIWsoPgxKCFihqngd7sXvvBGTlGmNrGEWAsmI4vH5HsWUp5pLomcZyHrvKWcGyfISQ==",
+      "version": "0.30.3",
+      "resolved": "https://registry.npmjs.org/@uppy/core/-/core-0.30.3.tgz",
+      "integrity": "sha512-UDcFV9WnghOAZecg5oKnXEj97CTdqKxMuajkmhGC64rS5Ef3tcTB5JreKVEAvC/z8DgCAqrPex39+vkafns7cA==",
       "requires": {
-        "@uppy/store-default": "0.27.1",
-        "@uppy/utils": "0.29.1",
+        "@uppy/store-default": "0.28.3",
+        "@uppy/utils": "0.30.3",
         "cuid": "^2.1.1",
         "lodash.throttle": "^4.1.1",
         "mime-match": "^1.0.2",
         "namespace-emitter": "^2.0.1",
         "preact": "^8.2.9",
         "prettier-bytes": "^1.0.4"
+      },
+      "dependencies": {
+        "@uppy/utils": {
+          "version": "0.30.3",
+          "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-0.30.3.tgz",
+          "integrity": "sha512-v0+3+p70Rl4qMS5p5+n89Oa/Z61FAitcJ8HS06NHiGo2HArO8VseBBAbNncF/SdUqczWhz7dWQ3/uXUx8jli3Q==",
+          "requires": {
+            "lodash.throttle": "^4.1.1"
+          }
+        }
       }
     },
     "@uppy/dashboard": {
@@ -991,9 +1001,9 @@
       }
     },
     "@uppy/store-default": {
-      "version": "0.27.1",
-      "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-0.27.1.tgz",
-      "integrity": "sha512-y+L1kUUZqV4QforOkl/prd3hOErgFWUvFx+tqRbAMgccsxYk8PapvUe42FZPa7Z92iIqbOohlJe8ZsIj4+2tzg=="
+      "version": "0.28.3",
+      "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-0.28.3.tgz",
+      "integrity": "sha512-H3dHvYnna1D3qGMeEW2Mc4BDe2+73IsshqyqyNawZcOG4EF053D5ZeeoB0DQoXaL290vsHMhYilZbp6O0v6Z8g=="
     },
     "@uppy/thumbnail-generator": {
       "version": "0.29.1",
@@ -1031,6 +1041,25 @@
         "lodash.throttle": "^4.1.1"
       }
     },
+    "@uppy/webcam": {
+      "version": "0.30.3",
+      "resolved": "https://registry.npmjs.org/@uppy/webcam/-/webcam-0.30.3.tgz",
+      "integrity": "sha512-fIUaOPrPVvapiL7+N+2wdtlRe2W0vHAHq39DNs2Q8HesjACxpAWf7vlVPZXutMlvqV6hIQWXxSGUoIS2xSVkLA==",
+      "requires": {
+        "@uppy/utils": "0.30.3",
+        "preact": "^8.2.9"
+      },
+      "dependencies": {
+        "@uppy/utils": {
+          "version": "0.30.3",
+          "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-0.30.3.tgz",
+          "integrity": "sha512-v0+3+p70Rl4qMS5p5+n89Oa/Z61FAitcJ8HS06NHiGo2HArO8VseBBAbNncF/SdUqczWhz7dWQ3/uXUx8jli3Q==",
+          "requires": {
+            "lodash.throttle": "^4.1.1"
+          }
+        }
+      }
+    },
     "abbrev": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -2574,9 +2603,9 @@
       }
     },
     "cuid": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/cuid/-/cuid-2.1.4.tgz",
-      "integrity": "sha512-l1vrCiWOwBpu85bfm939Hg3MQh2alxAMoGZnjcJOYkgN7wzy9yi3vQhRzwcTr9mdIlfTp8DP9G5ZgIIPyaQEvg=="
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/cuid/-/cuid-2.1.6.tgz",
+      "integrity": "sha512-ZFp7PS6cSYMJNch9fc3tyHdE4T8TDo3Y5qAxb0KSA9mpiYDo7z9ql1CznFuuzxea9STVIDy0tJWm2lYiX2ZU1Q=="
     },
     "date-now": {
       "version": "0.1.4",

+ 7 - 6
examples/bundled/package.json

@@ -8,11 +8,12 @@
     "parcel-bundler": "^1.11.0"
   },
   "dependencies": {
-    "@uppy/core": "^0.29.1",
-    "@uppy/dashboard": "^0.29.1",
-    "@uppy/google-drive": "^0.29.1",
-    "@uppy/instagram": "^0.29.1",
-    "@uppy/tus": "^0.29.1",
-    "@uppy/url": "^0.29.1"
+    "@uppy/core": "^0.30.3",
+    "@uppy/dashboard": "^0.30.3",
+    "@uppy/google-drive": "^0.30.3",
+    "@uppy/instagram": "^0.30.3",
+    "@uppy/tus": "^0.30.3",
+    "@uppy/url": "^0.30.3",
+    "@uppy/webcam": "^0.30.3"
   }
 }

+ 2 - 2
examples/cdn-example/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.css" rel="stylesheet">
+    <link href="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.js"></script>
+    <script src="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

+ 26 - 2
examples/dev/index.html

@@ -14,11 +14,35 @@
 
       #upload-form {
         max-width: 400px;
-        margin: auto;
         text-align: left;
+        margin: auto;
+      }
+
+      a {
+        color: purple;
+      }
+
+      button,
+      input {
+        color: green;
+        font-size: 30px;
+        text-align: right;
+        border: 2px solid purple;
+      }
+
+      ul {
+        margin: 60px;
+      }
+
+      li {
+        margin: 60px;
+      }
+
+      .foo a {
+        color: purple;
       }
     </style>
-    <main>
+    <main class="foo">
       <h1>Uppy is here</h1>
 
       <form id="upload-form" action="/">

+ 4 - 1
examples/dev/main.js

@@ -6,9 +6,11 @@ const GoogleDrive = require('./../../packages/@uppy/google-drive/src')
 const Url = require('./../../packages/@uppy/url/src')
 const Webcam = require('./../../packages/@uppy/webcam/src')
 const Tus = require('./../../packages/@uppy/tus/src')
+// const XHRUpload = require('./../../packages/@uppy/xhr-upload/src')
 const Form = require('./../../packages/@uppy/form/src')
 
 const TUS_ENDPOINT = 'https://master.tus.io/files/'
+// const XHR_ENDPOINT = 'https://api2.transloadit.com'
 
 const uppy = Uppy({
   debug: true,
@@ -20,7 +22,7 @@ const uppy = Uppy({
   .use(Dashboard, {
     trigger: '#pick-files',
     // inline: true,
-    // target: 'body',
+    target: '.foo',
     metaFields: [
       { id: 'license', name: 'License', placeholder: 'specify license' },
       { id: 'caption', name: 'Caption', placeholder: 'add caption' }
@@ -35,6 +37,7 @@ const uppy = Uppy({
   .use(Url, { target: Dashboard, serverUrl: 'http://localhost:3020' })
   .use(Webcam, { target: Dashboard })
   .use(Tus, { endpoint: TUS_ENDPOINT })
+  // .use(XHRUpload, { endpoint: XHR_ENDPOINT })
   .use(Form, { target: '#upload-form' })
   // .use(GoldenRetriever, {serviceWorker: true})
 

+ 1 - 1
examples/dev/package.json

@@ -6,7 +6,7 @@
     "watchify": "^3.11.0"
   },
   "scripts": {
-    "watch": "watchify -t babelify -t aliasify main.js -o bundle.js -vd"
+    "watch:sandbox": "watchify -t babelify -t aliasify main.js -o bundle.js -vd"
   },
   "aliasify": {
     "aliases": {

ファイルの差分が大きいため隠しています
+ 459 - 150
examples/digitalocean-spaces/package-lock.json


+ 2 - 2
examples/digitalocean-spaces/package.json

@@ -9,8 +9,8 @@
     "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
     "body-parser": "^1.18.3",
-    "budo": "^11.3.2",
-    "cors": "^2.8.4",
+    "budo": "^11.6.1",
+    "cors": "^2.8.5",
     "router": "^1.3.3"
   }
 }

ファイルの差分が大きいため隠しています
+ 479 - 142
examples/multiple-instances/package-lock.json


+ 1 - 1
examples/multiple-instances/package.json

@@ -15,6 +15,6 @@
     "aliasify": "^2.1.0",
     "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
-    "budo": "^11.3.2"
+    "budo": "^11.6.1"
   }
 }

ファイルの差分が大きいため隠しています
+ 456 - 146
examples/react-example/package-lock.json


+ 1 - 1
examples/react-example/package.json

@@ -15,7 +15,7 @@
     "babel-core": "^6.26.3",
     "babel-preset-react": "^6.24.1",
     "babelify": "^8.0.0",
-    "budo": "^11.3.2",
+    "budo": "^11.6.1",
     "react": "^15.6.2",
     "react-dom": "^15.6.2"
   }

ファイルの差分が大きいため隠しています
+ 457 - 147
examples/redux/package-lock.json


+ 4 - 4
examples/redux/package.json

@@ -11,11 +11,11 @@
     }
   },
   "dependencies": {
-    "babel-core": "^6.26.3",
-    "redux": "^4.0.0",
-    "redux-logger": "^3.0.6",
     "aliasify": "^2.1.0",
+    "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
-    "budo": "^11.3.2"
+    "budo": "^11.6.1",
+    "redux": "^4.0.1",
+    "redux-logger": "^3.0.6"
   }
 }

+ 29 - 3
examples/transloadit-textarea/index.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
   <head>
-    <link rel="stylesheet" href="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.css">
+    <link rel="stylesheet" href="https://transloadit.edgly.net/releases/uppy/v0.30.3/robodog.css">
     <style>
       body {
         font-family: Roboto, Open Sans;
@@ -26,7 +26,8 @@
         border-radius: 5px;
       }
 
-      main h2 { margin-top: 0 }
+      main p:first-child { margin-top: 0 }
+
       label {
         display: flex;
         padding-bottom: 16px;
@@ -95,6 +96,19 @@
       .snippet {
         margin-top: 25px;
       }
+
+      /* temp uppy fix, there was a typo in class name */
+      /* remove after uppy@>0.30.3 */
+      .uppy-DashboardAddFiles {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+        height: 100%;
+        position: relative;
+        text-align: center;
+        flex: 1;
+      }
     </style>
   </head>
   <body>
@@ -102,6 +116,14 @@
       <h1>Markdown Bin</h1>
     </header>
     <main>
+      <p>
+      Markdown Bin is a demo app that works a bit like Github Gists or pastebin. You can add markdown snippets, and add file attachments to each snippet by clicking "Upload an attachment" or by dragging files onto the text area. Transloadit generates an inline preview image for images, videos, and audio files. <a target="_blank" href="https://github.com/transloadit/uppy/blob/master/examples/transloadit-textarea/template.json">&raquo;&nbsp;View the Assembly Template here.</a>
+      </p>
+
+      <p>
+        ⚠️ For this demo, snippets are stored locally in your browser. Attachments are stored in Transloadit's temporary storage and expire after about 24 hours. In a real app, you can easily export files to a permanent storage solution like Amazon S3 or Google Cloud. <a target="_blank" href="https://transloadit.com/docs/#17-saving-conversion-results">&raquo;&nbsp;Learn more</a>
+      </p>
+
       <form id="new">
         <h2>Create a new snippet</h2>
         <label>
@@ -117,7 +139,11 @@
           </button>
         </p>
       </form>
-      <div id="snippets"></div>
+
+      <h2>Previous snippets</h2>
+
+      <div id="snippets">
+      </div>
     </main>
     <template id="snippet">
       <div class="snippet">

+ 22 - 105
examples/transloadit-textarea/main.js

@@ -1,105 +1,22 @@
 /* eslint-env browser */
 const marked = require('marked')
 const dragdrop = require('drag-drop')
-const transloadit = require('@uppy/robodog')
-
-// TOP SECRET!!!!!!!
-const TRANSLOADIT_KEY = '05a61ed019fe11e783fdbd1f56c73eb0'
-
-const THUMB_SIZE = [400, 300]
-
-/* eslint-disable no-template-curly-in-string */
-const IMAGE_FILTER = ['${file.mime}', 'regex', 'image/']
-const VIDEO_FILTER = ['${file.mime}', 'regex', 'video/']
-const AUDIO_FILTER = ['${file.mime}', 'regex', 'audio/']
-/* eslint-enable no-template-curly-in-string */
-
-const transloaditSteps = {
-  ':original': {
-    robot: '/upload/handle'
-  },
-
-  // Separate source files
-
-  images: {
-    use: [':original'],
-    robot: '/file/filter',
-    result: true,
-    accepts: [IMAGE_FILTER]
-  },
-  videos: {
-    use: [':original'],
-    robot: '/file/filter',
-    result: true,
-    accepts: [VIDEO_FILTER]
-  },
-  audios: {
-    use: [':original'],
-    robot: '/file/filter',
-    result: true,
-    accepts: [AUDIO_FILTER]
-  },
-  others: {
-    use: [':original'],
-    robot: '/file/filter',
-    result: true,
-    rejects: [IMAGE_FILTER, VIDEO_FILTER, AUDIO_FILTER]
-  },
-
-  // Generate thumbs for different types of files
-
-  audio_thumbnails: {
-    use: ['audios'],
-    robot: '/audio/artwork'
-  },
-  resized_thumbnails: {
-    use: ['images', 'audio_thumbnails'],
-    robot: '/image/resize',
-    imagemagick_stack: 'v1.0.0',
-    width: THUMB_SIZE[0],
-    height: THUMB_SIZE[1],
-    resize_strategy: 'fit',
-    zoom: false
-  },
-  video_thumbnails: {
-    use: ['videos'],
-    robot: '/video/thumbs',
-    ffmpeg_stack: 'v2.2.3',
-    count: 1,
-    offsets: ['50%'],
-    format: 'jpeg',
-    width: THUMB_SIZE[0],
-    height: THUMB_SIZE[1],
-    resize_strategy: 'fit'
-  },
-
-  // Optimize thumbnails for decent file size
-
-  thumbnails: {
-    use: ['resized_thumbnails', 'video_thumbnails'],
-    robot: '/image/optimize'
-  },
-
-  // Store all the things away
-
-  store_sources: {
-    use: ['images', 'videos', 'audios', 'others'],
-    robot: '/s3/store',
-    credentials: 'uppy_test_s3',
-    // eslint-disable-next-line no-template-curly-in-string
-    path: 'markdownbin/sources/${unique_prefix}/${file.url_name}',
-    result: true
-  },
-  store_thumbnails: {
-    use: ['thumbnails'],
-    robot: '/s3/store',
-    credentials: 'uppy_test_s3',
-    // eslint-disable-next-line no-template-curly-in-string
-    path: 'markdownbin/thumbs/${file.md5hash}',
-    result: true
-  }
-}
-
+const robodog = require('@uppy/robodog')
+
+const TRANSLOADIT_EXAMPLE_KEY = '35c1aed03f5011e982b6afe82599b6a0'
+const TRANSLOADIT_EXAMPLE_TEMPLATE = '0b2ee2bc25dc43619700c2ce0a75164a'
+
+/**
+ * A textarea for markdown text, with support for file attachments.
+ *
+ * ## Usage
+ *
+ * ```js
+ * const element = document.querySelector('textarea')
+ * const mdtxt = new MarkdownTextarea(element)
+ * mdtxt.install()
+ * ```
+ */
 class MarkdownTextarea {
   constructor (element) {
     this.element = element
@@ -185,11 +102,11 @@ class MarkdownTextarea {
   }
 
   uploadFiles (files) {
-    transloadit.upload({
+    robodog.upload({
       waitForEncoding: true,
       params: {
-        auth: { key: TRANSLOADIT_KEY },
-        steps: transloaditSteps
+        auth: { key: TRANSLOADIT_EXAMPLE_KEY },
+        template_id: TRANSLOADIT_EXAMPLE_TEMPLATE
       }
     }).then((result) => {
       this.insertAttachments(
@@ -202,11 +119,11 @@ class MarkdownTextarea {
   }
 
   pickFiles () {
-    transloadit.pick({
+    robodog.pick({
       waitForEncoding: true,
       params: {
-        auth: { key: TRANSLOADIT_KEY },
-        steps: transloaditSteps
+        auth: { key: TRANSLOADIT_EXAMPLE_KEY },
+        template_id: TRANSLOADIT_EXAMPLE_TEMPLATE
       }
     }).then((result) => {
       this.insertAttachments(

+ 93 - 0
examples/transloadit-textarea/template.json

@@ -0,0 +1,93 @@
+{
+  "steps": {
+    ":original": {
+      "robot": "/upload/handle"
+    },
+
+    "images": {
+      "use": [
+        ":original"
+      ],
+      "robot": "/file/filter",
+      "result": true,
+      "accepts": [
+        ["${file.mime}", "regex", "image/"]
+      ]
+    },
+    "videos": {
+      "use": [
+        ":original"
+      ],
+      "robot": "/file/filter",
+      "result": true,
+      "accepts": [
+        ["${file.mime}", "regex", "video/"]
+      ]
+    },
+    "audios": {
+      "use": [
+        ":original"
+      ],
+      "robot": "/file/filter",
+      "result": true,
+      "accepts": [
+        ["${file.mime}", "regex", "audio/"]
+      ]
+    },
+    "others": {
+      "use": [
+        ":original"
+      ],
+      "robot": "/file/filter",
+      "result": true,
+      "rejects": [
+        ["${file.mime}", "regex", "image/"],
+        ["${file.mime}", "regex", "video/"],
+        ["${file.mime}", "regex", "audio/"]
+      ]
+    },
+
+    "audio_thumbnails": {
+      "use": [
+        "audios"
+      ],
+      "robot": "/audio/artwork",
+      "ffmpeg_stack": "v3.3.3"
+    },
+    "resized_thumbnails": {
+      "use": [
+        "images",
+        "audio_thumbnails"
+      ],
+      "robot": "/image/resize",
+      "imagemagick_stack": "v1.0.0",
+      "width": 400,
+      "height": 300,
+      "resize_strategy": "fit",
+      "zoom": false
+    },
+    "video_thumbnails": {
+      "use": [
+        "videos"
+      ],
+      "robot": "/video/thumbs",
+      "ffmpeg_stack": "v3.3.3",
+      "count": 1,
+      "offsets": [
+        "50%"
+      ],
+      "format": "jpeg",
+      "width": 400,
+      "height": 300,
+      "resize_strategy": "fit"
+    },
+    "thumbnails": {
+      "use": [
+        "resized_thumbnails",
+        "video_thumbnails"
+      ],
+      "robot": "/image/optimize",
+      "result": true
+    }
+  }
+}

+ 2 - 2
examples/uppy-with-companion/client/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.css" rel="stylesheet">
+    <link href="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://transloadit.edgly.net/releases/uppy/v0.30.2/uppy.min.js"></script>
+    <script src="https://transloadit.edgly.net/releases/uppy/v0.30.3/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

ファイルの差分が大きいため隠しています
+ 470 - 294
examples/xhr-bundle/package-lock.json


+ 5 - 5
examples/xhr-bundle/package.json

@@ -16,10 +16,10 @@
     "aliasify": "^2.1.0",
     "babel-core": "^6.26.3",
     "babelify": "^8.0.0",
-    "budo": "^11.3.2",
-    "cors": "^2.8.4",
-    "express": "^4.16.3",
-    "multer": "^1.3.1",
-    "npm-run-all": "^4.1.3"
+    "budo": "^11.6.1",
+    "cors": "^2.8.5",
+    "express": "^4.16.4",
+    "multer": "^1.4.1",
+    "npm-run-all": "^4.1.5"
   }
 }

+ 0 - 3
locales/README.md

@@ -1,3 +0,0 @@
-# Unused
-
-These locale files are not currently used by Uppy. We are keeping them around because they will, hopefully, be used in the future.

+ 0 - 63
locales/cs_CZ.js

@@ -1,63 +0,0 @@
-/* eslint camelcase: 0 */
-
-const cs_CZ = {}
-
-cs_CZ.strings = {
-  chooseFile: 'Vyberte soubor',
-  orDragDrop: 'nebo ho sem přetáhněte',
-  youHaveChosen: 'Vybrali jste: %{fileName}',
-  filesChosen: {
-    0: '%{smart_count} soubor vybrán',
-    1: '%{smart_count} soubory vybrány',
-    2: '%{smart_count} souborů vybráno'
-  },
-  filesUploaded: {
-    0: '%{smart_count} soubor nahrán',
-    1: '%{smart_count} soubory nahrány',
-    2: '%{smart_count} souborů nahráno'
-  },
-  files: {
-    0: '%{smart_count} soubor',
-    1: '%{smart_count} soubory',
-    2: '%{smart_count} souborů'
-  },
-  uploadFiles: {
-    0: 'Nahrát %{smart_count} soubor',
-    1: 'Nahrát %{smart_count} soubory',
-    2: 'Nahrát %{smart_count} souborů'
-  },
-  selectToUpload: 'Vybrat soubory k nahrání',
-  closeModal: 'Zavřít okno',
-  upload: 'Nahrát',
-  importFrom: 'Importovat soubory z',
-  dashboardWindowTitle: 'Uppy Dashboard okno (Pro zavření stiskněte Escape)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Odkaz zkopírován do schránky.',
-  copyLinkToClipboardFallback: 'Zkopírovat následující odkaz',
-  done: 'Hotovo',
-  localDisk: 'Disk',
-  dropPasteImport: 'Přetáhněte soubory, vložte je, importujte je z některých výše uvedených služeb, nebo',
-  dropPaste: 'Přetáhněte soubory, vložte je, nebo',
-  browse: 'procházejte',
-  fileProgress: 'Nahrávání: rychlost nahrávání a zbývající čas',
-  numberOfSelectedFiles: 'Počet vybraných souborů',
-  uploadAllNewFiles: 'Nahrát všechny nové soubory'
-}
-
-cs_CZ.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-
-  if (n >= 2 && n <= 4) {
-    return 1
-  }
-
-  return 2
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.cs_CZ = cs_CZ
-}
-
-module.exports = cs_CZ

+ 0 - 54
locales/de_DE.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const de_DE = {}
-
-de_DE.strings = {
-  chooseFile: 'Wähle eine Datei',
-  youHaveChosen: 'Du hast gewählt: %{fileName}',
-  orDragDrop: 'oder schiebe Sie hier her',
-  filesChosen: {
-    0: '%{smart_count} Datei gewählt',
-    1: '%{smart_count} Dateien gewählt'
-  },
-  filesUploaded: {
-    0: '%{smart_count} Datei hochgeladen',
-    1: '%{smart_count} Dateien hochgeladen'
-  },
-  files: {
-    0: '%{smart_count} Datei',
-    1: '%{smart_count} Dateien'
-  },
-  uploadFiles: {
-    0: 'Upload %{smart_count} Datei',
-    1: 'Upload %{smart_count} Dateien'
-  },
-  selectToUpload: 'Ausgewählten Dateien wurden hochgeladen',
-  closeModal: 'Schließen Modal',
-  upload: 'Hochladen',
-  importFrom: 'Importiere Daten von',
-  dashboardWindowTitle: 'Uppy Dashboard Fenster (Drücke Escape zum schließen)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Link wurde in Zwischenablage kopiert.',
-  copyLinkToClipboardFallback: 'Kopiere die untere URL',
-  done: 'Fertig',
-  localDisk: 'Lokale Festplatte',
-  dropPasteImport: 'Ziehe Dateien hier her, einfügen, importieren aus einer der oberen Quellen oder',
-  dropPaste: 'Zihe Dateien hier her, einfügen oder',
-  browse: 'Durchsuchen',
-  fileProgress: 'Datei Fortschritt: Upload Geschwindigkeit und ETA',
-  numberOfSelectedFiles: 'Anzahl gewählter Dateien',
-  uploadAllNewFiles: 'Alle neuen Dateien hochladen'
-}
-
-de_DE.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.de_DE = de_DE
-}
-
-module.exports = de_DE

+ 0 - 54
locales/en_US.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const en_US = {}
-
-en_US.strings = {
-  chooseFile: 'Choose a file',
-  youHaveChosen: 'You have chosen: %{fileName}',
-  orDragDrop: 'or drag it here',
-  filesChosen: {
-    0: '%{smart_count} file selected',
-    1: '%{smart_count} files selected'
-  },
-  filesUploaded: {
-    0: '%{smart_count} file uploaded',
-    1: '%{smart_count} files uploaded'
-  },
-  files: {
-    0: '%{smart_count} file',
-    1: '%{smart_count} files'
-  },
-  uploadFiles: {
-    0: 'Upload %{smart_count} file',
-    1: 'Upload %{smart_count} files'
-  },
-  selectToUpload: 'Select files to upload',
-  closeModal: 'Close Modal',
-  upload: 'Upload',
-  importFrom: 'Import files from',
-  dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Link copied to clipboard.',
-  copyLinkToClipboardFallback: 'Copy the URL below',
-  done: 'Done',
-  localDisk: 'Local Disk',
-  dropPasteImport: 'Drop files here, paste, import from one of the locations above or',
-  dropPaste: 'Drop files here, paste or',
-  browse: 'browse',
-  fileProgress: 'File progress: upload speed and ETA',
-  numberOfSelectedFiles: 'Number of selected files',
-  uploadAllNewFiles: 'Upload all new files'
-}
-
-en_US.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.en_US = en_US
-}
-
-module.exports = en_US

+ 0 - 54
locales/es_ES.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const es_ES = {}
-
-es_ES.strings = {
-  chooseFile: 'Selecciona un fichero',
-  youHaveChosen: 'Has seleccionado: %{fileName}',
-  orDragDrop: 'o arrástralo aquí',
-  filesChosen: {
-    0: '%{smart_count} fichero seleccionado',
-    1: '%{smart_count} ficheros seleccionados'
-  },
-  filesUploaded: {
-    0: '%{smart_count} fichero subido',
-    1: '%{smart_count} ficheros subidos'
-  },
-  files: {
-    0: '%{smart_count} fichero',
-    1: '%{smart_count} ficheros'
-  },
-  uploadFiles: {
-    0: 'Subir %{smart_count} fichero',
-    1: 'Subir %{smart_count} ficheros'
-  },
-  selectToUpload: 'Selecciona los ficheros a subir',
-  closeModal: 'Cerrar modal',
-  upload: 'Subir',
-  importFrom: 'Importar ficheros desde',
-  dashboardWindowTitle: 'Panel de Uppy (Pulsa escape para cerrar)',
-  dashboardTitle: 'Panel de Uppy',
-  copyLinkToClipboardSuccess: 'Enlace copiado al portapapeles.',
-  copyLinkToClipboardFallback: 'Copiar la siguiente URL',
-  done: 'Hecho',
-  localDisk: 'Disco local',
-  dropPasteImport: 'Arrasta ficheros aquí, pega, importa de alguno de los servicios de arriba o',
-  dropPaste: 'Arrastra ficheros aquí, pega o',
-  browse: 'navegar',
-  fileProgress: 'Progreso: velocidad de subida y tiempo estimado',
-  numberOfSelectedFiles: 'Número de ficheros seleccionados',
-  uploadAllNewFiles: 'Subir todos los nuevos ficheros'
-}
-
-es_ES.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.es_ES = es_ES
-}
-
-module.exports = es_ES

+ 0 - 54
locales/fi_FI.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const fi_FI = {}
-
-fi_FI.strings = {
-  chooseFile: 'Valitse tiedosto',
-  youHaveChosen: 'Valitsit: %{fileName}',
-  orDragDrop: 'tai raahaa se tähän',
-  filesChosen: {
-    0: '%{smart_count} tiedosto valittu',
-    1: '%{smart_count} tiedostoa valittu'
-  },
-  filesUploaded: {
-    0: '%{smart_count} tiedosto siirretty',
-    1: '%{smart_count} tiedostoa siirretty'
-  },
-  files: {
-    0: '%{smart_count} tiedosto',
-    1: '%{smart_count} tiedostoa'
-  },
-  uploadFiles: {
-    0: 'Siirrä %{smart_count} tiedosto',
-    1: 'Siirrä %{smart_count} tiedostoa'
-  },
-  selectToUpload: 'Valitse siirrettävät tiedostot',
-  closeModal: 'Sulje ikkuna',
-  upload: 'Siirrä',
-  importFrom: 'Tuo tiedostoja',
-  dashboardWindowTitle: 'Uppy-ohjausnäkymä (Sulje Esc-näppäimellä)',
-  dashboardTitle: 'Uppy-ohjausnäkymä',
-  copyLinkToClipboardSuccess: 'Linkki kopioitu leikepöydälle.',
-  copyLinkToClipboardFallback: 'Kopioi allaoleva linkki',
-  done: 'Valmis',
-  localDisk: 'Paikallinen levy',
-  dropPasteImport: 'Pudota tiedosto(t) tähän, liitä, tuo tiedostoja ylläolevista sijainneista tai',
-  dropPaste: 'Pudota tiedosto(t) tähän, liitä tai',
-  browse: 'selaa',
-  fileProgress: 'Siirron edistyminen: lähetysnopeus ja arvioitu valmistumisaika',
-  numberOfSelectedFiles: 'Valittujen tiedostojen lukumäärä',
-  uploadAllNewFiles: 'Siirrä kaikki uudet tiedostot'
-}
-
-fi_FI.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.fi_FI = fi_FI
-}
-
-module.exports = fi_FI

+ 0 - 54
locales/id_ID.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const id_ID = {}
-
-id_ID.strings = {
-  chooseFile: 'Pilih berkas',
-  youHaveChosen: 'Berkas yang dipilih: %{fileName}',
-  orDragDrop: 'atau tarik dan taruh berkas ke sini',
-  filesChosen: {
-    0: '%{smart_count} berkas dipilih',
-    1: '%{smart_count} berkas dipilih'
-  },
-  filesUploaded: {
-    0: '%{smart_count} berkas terunggah',
-    1: '%{smart_count} berkas terunggah'
-  },
-  files: {
-    0: '%{smart_count} berkas',
-    1: '%{smart_count} berkas'
-  },
-  uploadFiles: {
-    0: 'Unggah %{smart_count} berkas',
-    1: 'Unggah %{smart_count} berkas'
-  },
-  selectToUpload: 'Pilih berkas untuk mengunggah',
-  closeModal: 'Tutup Modal',
-  upload: 'Unggah',
-  importFrom: 'Import berkas dari',
-  dashboardWindowTitle: 'Uppy Beranda Window (Tekan escape untuk menutup)',
-  dashboardTitle: 'Beranda Uppy',
-  copyLinkToClipboardSuccess: 'Link tersalin.',
-  copyLinkToClipboardFallback: 'Salin URL di bawah ini',
-  done: 'Selesai',
-  localDisk: 'Penyimpanan Lokal',
-  dropPasteImport: 'Taruh berkas di sini, tempel, import dari salah satu lokasi di atas atau',
-  dropPaste: 'Taruh berkas di sini, tempel atau',
-  browse: 'cari',
-  fileProgress: 'Proses berkas: kecepatan unggah dan ETA',
-  numberOfSelectedFiles: 'Total berkas yang di pilih',
-  uploadAllNewFiles: 'Unggah semua berkas baru'
-}
-
-id_ID.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.id_ID = id_ID
-}
-
-module.exports = id_ID

+ 0 - 54
locales/it_IT.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const it_IT = {}
-
-it_IT.strings = {
-  chooseFile: 'Seleziona un file',
-  youHaveChosen: 'Hai scelto: %{fileName}',
-  orDragDrop: 'oppure trascinalo qui',
-  filesChosen: {
-    0: '%{smart_count} file selezionato',
-    1: '%{smart_count} file selezionati'
-  },
-  filesUploaded: {
-    0: '%{smart_count} file caricato',
-    1: '%{smart_count} file caricati'
-  },
-  files: {
-    0: '%{smart_count} file',
-    1: '%{smart_count} file'
-  },
-  uploadFiles: {
-    0: 'Carica %{smart_count} file',
-    1: 'Carica %{smart_count} file'
-  },
-  selectToUpload: 'Seleziona i file da caricare',
-  closeModal: 'Chiudi la finestra',
-  upload: 'Carica',
-  importFrom: 'Importa i file da',
-  dashboardWindowTitle: 'Uppy Dashboard Window (Premi escape per chiuderla)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Collegamento copiato negli appunti.',
-  copyLinkToClipboardFallback: 'Copia il seguente indirizzo',
-  done: 'Fatto',
-  localDisk: 'Disco locale',
-  dropPasteImport: 'Trascina i file qui, incolla, importa da uno dei servizi sopra oppure',
-  dropPaste: 'Trascina i file qui, incolla oppure',
-  browse: 'sfoglia',
-  fileProgress: 'Avanzamento del file: velocità di caricamento e tempo rimanente',
-  numberOfSelectedFiles: 'Numero di file selezionati',
-  uploadAllNewFiles: 'Carica tutti i nuovi file'
-}
-
-it_IT.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.it_IT = it_IT
-}
-
-module.exports = it_IT

+ 0 - 54
locales/nb_NO.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const nb_NO = {}
-
-nb_NO.strings = {
-  chooseFile: 'Velg en fil',
-  youHaveChosen: 'Du har valgt: %{fileName}',
-  orDragDrop: 'eller slipp den her',
-  filesChosen: {
-    0: '%{smart_count} fil valgt',
-    1: '%{smart_count} filer valgt'
-  },
-  filesUploaded: {
-    0: '%{smart_count} fil lastet opp',
-    1: '%{smart_count} filer lastet opp'
-  },
-  files: {
-    0: '%{smart_count} fil',
-    1: '%{smart_count} filer'
-  },
-  uploadFiles: {
-    0: 'Lastet opp %{smart_count} fil',
-    1: 'Lastet opp %{smart_count} filer'
-  },
-  selectToUpload: 'Velg filer å laste opp',
-  closeModal: 'Lukk dialogboksen',
-  upload: 'Last opp',
-  importFrom: 'Importer filer fra',
-  dashboardWindowTitle: 'Uppy Dashboard-vindu (Trykk escape for å lukke)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Lenken ble kopiert til utklippstavla.',
-  copyLinkToClipboardFallback: 'Kopier URL-en under',
-  done: 'Ferdig',
-  localDisk: 'Lokal disk',
-  dropPasteImport: 'Du kan slippe eller lime inn filer her, importere fra en en av plasseringene ovenfor eller',
-  dropPaste: 'Du kan slippe eller lime inn filer her eller',
-  browse: 'velge dem',
-  fileProgress: 'Filstatus: Opplastingshastighet og ETA',
-  numberOfSelectedFiles: 'Antall valgte filer',
-  uploadAllNewFiles: 'Last opp alle nye filer'
-}
-
-nb_NO.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.nb_NO = nb_NO
-}
-
-module.exports = nb_NO

+ 0 - 61
locales/pl_PL.js

@@ -1,61 +0,0 @@
-/* eslint camelcase: 0 */
-
-const pl_PL = {}
-
-pl_PL.strings = {
-  chooseFile: 'Wybierz plik',
-  youHaveChosen: 'Wybrałeś: %{fileName}',
-  orDragDrop: 'lub przeciągnij tutaj',
-  filesChosen: {
-    0: '%{smart_count} wybrany plik',
-    1: '%{smart_count} wybrane pliki',
-    2: '%{smart_count} wybranych plików'
-  },
-  filesUploaded: {
-    0: '%{smart_count} wysłany plik',
-    1: '%{smart_count} wysłane pliki',
-    2: '%{smart_count} wysłanych plików'
-  },
-  files: {
-    0: '%{smart_count} plik',
-    1: '%{smart_count} pliki',
-    2: '%{smart_count} plików'
-  },
-  uploadFiles: {
-    0: 'Wyślij %{smart_count} plik',
-    1: 'Wyślij %{smart_count} pliki',
-    2: 'Wyślij %{smart_count} plików'
-  },
-  selectToUpload: 'Wybierz pliki do wysłania',
-  closeModal: 'Zamknij okno',
-  upload: 'Wyślij',
-  importFrom: 'Zaimportuj pliki z',
-  dashboardWindowTitle: 'Okno Uppy Dashboard (Wciśnij esc, aby zamknąć)',
-  dashboardTitle: 'Uppy Dashboard',
-  copyLinkToClipboardSuccess: 'Link skopiowany do schowka.',
-  copyLinkToClipboardFallback: 'Skopiuj poniższy link',
-  done: 'Gotowe',
-  localDisk: 'Dysk lokalny',
-  dropPasteImport: 'Upuść, wklej lub zaimportuj pliki tutaj albo',
-  dropPaste: 'Upuść lub wklej pliki tutaj albo',
-  browse: 'przeglądaj',
-  fileProgress: 'Postęp pliku: prędkość wysyłania i przewidywany pozostały czas',
-  numberOfSelectedFiles: 'Ilość wybranych plików',
-  uploadAllNewFiles: 'Wyślij wszystkie nowe pliki'
-}
-
-pl_PL.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  if (n >= 2 && n <= 4) {
-    return 1
-  }
-  return 2
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.pl_PL = pl_PL
-}
-
-module.exports = pl_PL

+ 0 - 52
locales/pt_BR.js

@@ -1,52 +0,0 @@
-/* eslint camelcase: 0 */
-
-const pt_BR = {}
-
-pt_BR.strings = {
-  chooseFile: 'Escolha um arquivo',
-  youHaveChosen: 'Você escolheu: %{fileName}',
-  orDragDrop: 'ou arraste-o aqui',
-  filesChosen: {
-    0: '%{smart_count} arquivo selecionado',
-    1: '%{smart_count} arquivos selecionados'
-  },
-  filesUploaded: {
-    0: '%{smart_count} arquivo enviado',
-    1: '%{smart_count} arquivos enviados'
-  },
-  files: {
-    0: '%{smart_count} arquivo',
-    1: '%{smart_count} arquivos'
-  },
-  uploadFiles: {
-    0: 'Enviar %{smart_count} arquivo',
-    1: 'Enviar %{smart_count} arquivos'
-  },
-  selectToUpload: 'Selecione arquivos para enviar',
-  closeModal: 'Fechar Modal',
-  upload: 'Enviar',
-  importFrom: 'Importar arquivos de',
-  dashboardWindowTitle: 'Painel do Uppy (Aperte Esc para fechar)',
-  dashboardTitle: 'Painel do Uppy',
-  copyLinkToClipboardSuccess: 'Link copiado para área de transferência.',
-  copyLinkToClipboardFallback: 'Copie a URL abaixo',
-  done: 'Finalizado',
-  localDisk: 'Disco Local',
-  dropPasteImport: 'Arraste arquivos até aqui, cole-os ou importe de:',
-  fileProgress: 'Progresso de Arquivo: velocidade de envio e estimativas',
-  numberOfSelectedFiles: 'Números de arquivos selecionados',
-  uploadAllNewFiles: 'Enviar todos os arquivos novos'
-}
-
-pt_BR.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.pt_BR = pt_BR
-}
-
-module.exports = pt_BR

+ 0 - 35
locales/ru_RU.js

@@ -1,35 +0,0 @@
-/* eslint camelcase: 0 */
-
-const ru_RU = {}
-
-ru_RU.strings = {
-  chooseFile: 'Выберите файл',
-  orDragDrop: 'или перенесите его сюда',
-  youHaveChosen: 'Вы выбрали: %{file_name}',
-  filesChosen: {
-    0: 'Выбран %{smart_count} файл',
-    1: 'Выбрано %{smart_count} файла',
-    2: 'Выбрано %{smart_count} файлов'
-  },
-  upload: 'Загрузить',
-  localDisk: 'Диск',
-  dropPasteImport: 'Перенесите файлы сюда, вставьте из буфера обмена или импортируйте из сервисов выше'
-}
-
-ru_RU.pluralize = function (n) {
-  if (n % 10 === 1 && n % 100 !== 11) {
-    return 0
-  }
-
-  if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) {
-    return 1
-  }
-
-  return 2
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.ru_RU = ru_RU
-}
-
-module.exports = ru_RU

+ 0 - 54
locales/tr_TR.js

@@ -1,54 +0,0 @@
-/* eslint camelcase: 0 */
-
-const tr_TR = {}
-
-tr_TR.strings = {
-  chooseFile: 'Dosya Seçin',
-  youHaveChosen: 'Seçmiş olduğun dosya: %{fileName}',
-  orDragDrop: 'yada bırakın',
-  filesChosen: {
-    0: '%{smart_count} adet dosya seçili',
-    1: '%{smart_count} adet dosyalar seçili'
-  },
-  filesUploaded: {
-    0: '%{smart_count} adet dosya yüklendi',
-    1: '%{smart_count} adet dosyalar yüklendi'
-  },
-  files: {
-    0: '%{smart_count} dosya',
-    1: '%{smart_count} dosyalar'
-  },
-  uploadFiles: {
-    0: 'Yüklenen %{smart_count} dosya',
-    1: 'Yüklenen %{smart_count} dosyalar'
-  },
-  selectToUpload: 'Yüklemek için dosyaları seçin',
-  closeModal: 'Pencereyi Kapat',
-  upload: 'Yükle',
-  importFrom: 'Dosyaları içeri aktar',
-  dashboardWindowTitle: 'Uppy Panel Pencerisi (kapatmak için esc kullanın)',
-  dashboardTitle: 'Uppy Panel',
-  copyLinkToClipboardSuccess: 'Bağlantı kopyalandı.',
-  copyLinkToClipboardFallback: 'Bağlantıyı kopyala.',
-  done: 'Bitti',
-  localDisk: 'Lokal Dosyalar',
-  dropPasteImport: 'Dosyaları buraya bırakın, yukarıdaki konumlardan birinden yapıştırın, içeri aktarın veya',
-  dropPaste: 'Dosyaları buraya bırak, yapıştır veya',
-  browse: 'Gözat',
-  fileProgress: 'Dosya ilerlemesi: yükleme hızı ve süresi',
-  numberOfSelectedFiles: 'Seçilen dosya sayısı',
-  uploadAllNewFiles: 'Tüm yeni dosyaları yükle'
-}
-
-tr_TR.pluralize = function (n) {
-  if (n === 1) {
-    return 0
-  }
-  return 1
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.tr_TR = tr_TR
-}
-
-module.exports = tr_TR

+ 0 - 34
locales/zh_CN.js

@@ -1,34 +0,0 @@
-/* eslint camelcase: 0 */
-
-const zh_CN = {}
-
-zh_CN.strings = {
-  chooseFile: '选择文件',
-  youHaveChosen: '你已经选择了: %{fileName}',
-  orDragDrop: '或者拖到这里来',
-  filesChosen: {
-    0: '已选 %{smart_count} 个文件'
-  },
-  filesUploaded: {
-    0: '已上传 %{smart_count} 个文件'
-  },
-  files: {
-    0: '%{smart_count} 个文件'
-  },
-  uploadFiles: {
-    0: '上传 %{smart_count} 个文件'
-  },
-  selectToUpload: '选择文件以上传',
-  closeModal: '关闭对话框',
-  upload: '上传'
-}
-
-zh_CN.pluralize = function (n) {
-  return 0
-}
-
-if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
-  window.Uppy.locales.zh_CN = zh_CN
-}
-
-module.exports = zh_CN

+ 1 - 1
netlify.toml

@@ -7,5 +7,5 @@ ID = "uppy"
 [context.deploy-preview]
 # netlify caches node_modules and doesn't run `npm install` after the first time,
 # so we have to `run bootstrap` manually in order to get lerna to do its thing
-command = "npm run bootstrap && npm run build && npm run web:install && npm run web:disc && npm run web:build"
+command = "npm run bootstrap && npm run build && npm run web:install && npm run web:inject-disc && npm run web:build"
 publish = "website/public"

ファイルの差分が大きいため隠しています
+ 252 - 244
package-lock.json


+ 57 - 57
package.json

@@ -6,10 +6,10 @@
   "lint-staged": {
     "*.js": "eslint"
   },
-  "pre-commit": "lint-staged",
+  "pre-commit": "lint:staged",
   "license": "MIT",
   "devDependencies": {
-    "@types/react": "^16.4.18",
+    "@types/react": "^16.8.10",
     "aliasify": "^2.1.0",
     "autoprefixer": "^7.2.6",
     "babel-cli": "^6.26.0",
@@ -27,17 +27,17 @@
     "browser-sync": "^2.26.3",
     "browserify": "^16.2.3",
     "chai": "^4.2.0",
-    "chalk": "^2.4.1",
+    "chalk": "^2.4.2",
     "cssnano": "^3.10.0",
     "disc": "^1.3.3",
-    "enzyme": "^3.7.0",
-    "enzyme-adapter-react-16": "^1.6.0",
+    "enzyme": "^3.9.0",
+    "enzyme-adapter-react-16": "^1.11.2",
     "eslint": "^3.19.0",
     "eslint-config-standard": "^10.2.1",
     "eslint-config-standard-preact": "^1.1.6",
-    "eslint-plugin-compat": "^2.6.3",
-    "eslint-plugin-import": "^2.14.0",
-    "eslint-plugin-jest": "^21.27.1",
+    "eslint-plugin-compat": "^2.7.0",
+    "eslint-plugin-import": "^2.16.0",
+    "eslint-plugin-jest": "^21.27.2",
     "eslint-plugin-node": "^4.2.3",
     "eslint-plugin-promise": "^3.8.0",
     "eslint-plugin-standard": "^3.1.0",
@@ -49,7 +49,7 @@
     "isomorphic-fetch": "2.2.1",
     "jest": "^23.6.0",
     "json3": "^3.3.2",
-    "lerna": "^3.13.0",
+    "lerna": "^3.13.1",
     "lint-staged": "^6.1.1",
     "minify-stream": "^1.2.0",
     "mkdirp": "0.5.1",
@@ -57,80 +57,80 @@
     "nock": "^9.6.1",
     "node-sass": "^4.11.0",
     "npm-auth-to-token": "^1.0.0",
-    "npm-run-all": "^4.1.3",
+    "npm-run-all": "^4.1.5",
     "onchange": "^4.1.0",
     "postcss": "^6.0.23",
     "postcss-safe-important": "^1.1.0",
     "pre-commit": "^1.2.2",
     "pretty-bytes": "^5.1.0",
-    "react": "^16.6.0",
-    "react-dom": "^16.6.0",
+    "react": "^16.8.6",
+    "react-dom": "^16.8.6",
     "redux": "^4.0.1",
     "replace-x": "^1.5.0",
     "temp-write": "^3.4.0",
-    "tinyify": "^2.4.3",
+    "tinyify": "^2.5.0",
+    "touch": "^3.1.0",
     "tsify": "^4.0.1",
     "typescript": "^2.9.2",
-    "verdaccio": "^3.11.4",
-    "watchify": "^3.11.0",
+    "verdaccio": "^3.11.6",
+    "watchify": "^3.11.1",
     "wdio-mocha-framework": "^0.6.4",
-    "wdio-sauce-service": "^0.4.12",
+    "wdio-sauce-service": "^0.4.14",
     "wdio-static-server-service": "^1.0.1",
-    "webdriverio": "^4.14.0"
+    "webdriverio": "^4.14.4"
   },
   "scripts": {
-    "build:bundle": "node ./bin/build-js.js",
-    "build:css": "node ./bin/build-css.js",
+    "bootstrap": "lerna bootstrap",
+    "build:bundle": "node ./bin/build-bundle.js",
+    "build:clean": "rm -rf packages/*/lib packages/@uppy/*/lib packages/*/dist packages/@uppy/*/dist",
     "build:companion": "cd ./packages/@uppy/companion && npm run build",
-    "build:gzip": "node ./bin/gzip.js",
-    "size": "echo 'JS Bundle mingz:' && cat ./packages/uppy/dist/uppy.min.js | gzip | wc -c && echo 'CSS Bundle mingz:' && cat ./packages/uppy/dist/uppy.min.css | gzip | wc -c",
+    "build:css": "node ./bin/build-css.js",
     "build:js": "npm-run-all build:lib build:bundle",
     "build:lib": "node ./bin/build-lib.js",
-    "build": "npm-run-all --parallel build:js build:css build:companion --serial build:gzip size",
-    "clean": "rm -rf packages/*/lib packages/@uppy/*/lib packages/*/dist packages/@uppy/*/dist",
+    "build": "npm-run-all --parallel build:js build:css build:companion --serial size",
+    "contributors:fetch": "githubcontrib --owner transloadit --repo uppy --cols 6 $([ \"${GITHUB_TOKEN:-}\" == \"\" ] && echo \"\" || echo \"--authToken ${GITHUB_TOKEN}\") --showlogin true --sortOrder desc",
+    "contributors:save": "replace-x -m '<!--contributors-->[\\s\\S]+<!--/contributors-->' \"<!--contributors-->\n## Contributors\n\n$(npm run --silent contributors:fetch)\n<!--/contributors-->\" README.md",
+    "dev:browsersync": "browser-sync start --no-open --no-ghost-mode false --server examples/dev --port 3452 --serveStatic packages/uppy/dist --files \"examples/dev/bundle.js, packages/uppy/dist/uppy.min.css, packages/uppy/lib/**/*\"",
+    "dev:watch-sandbox": "cd examples/dev && npm run watch:sandbox",
+    "dev:with-companion": "npm-run-all --parallel start:companion dev:watch-sandbox watch dev:browsersync",
+    "dev": "npm-run-all --parallel dev:watch-sandbox watch dev:browsersync",
     "lint:fix": "npm run lint -- --fix",
+    "lint:staged": "lint-staged",
     "lint": "eslint . --cache",
-    "lint-staged": "lint-staged",
     "release": "./bin/release",
-    "version": "./bin/sync-version-numbers",
-    "start:companion": "sh ./bin/companion",
-    "start": "npm-run-all --parallel watch start:companion web:preview",
-    "test:registry": "verdaccio --listen 4002 --config test/endtoend/verdaccio.yaml",
-    "test:build": "./bin/endtoend-build",
-    "test:build-ci": "./bin/endtoend-build-ci",
-    "test:prepare-ci": "npm-run-all --parallel --race test:registry test:build-ci",
-    "test:acceptance": "npm run test:prepare-ci && wdio test/endtoend/wdio.remote.conf.js",
-    "test:acceptance:local": "npm run test:build && wdio test/endtoend/wdio.local.conf.js",
-    "test:unit": "npm run build:lib && jest",
+    "size": "echo 'JS Bundle mingz:' && cat ./packages/uppy/dist/uppy.min.js | gzip | wc -c && echo 'CSS Bundle mingz:' && cat ./packages/uppy/dist/uppy.min.css | gzip | wc -c",
+    "start:companion": "./bin/companion",
+    "start": "npm-run-all --parallel watch start:companion web:start",
     "test:companion": "cd ./packages/@uppy/companion && npm run test",
+    "test:endtoend:build-ci": "./bin/endtoend-build-ci",
+    "test:endtoend:build": "./bin/endtoend-build",
+    "test:endtoend:local": "npm run test:endtoend:build && wdio test/endtoend/wdio.local.conf.js",
+    "test:endtoend:prepare-ci": "npm-run-all --parallel --race test:endtoend:registry test:endtoend:build-ci",
+    "test:endtoend:registry": "verdaccio --listen 4002 --config test/endtoend/verdaccio.yaml",
+    "test:endtoend": "npm run test:endtoend:prepare-ci && wdio test/endtoend/wdio.remote.conf.js",
     "test:type": "tsc -p .",
-    "test": "npm run lint && npm run test:unit && npm run test:type && npm run test:companion",
+    "test:unit": "npm run build:lib && jest",
     "test:watch": "jest --watch",
-    "travis:deletecache": "travis cache --delete",
+    "test": "npm-run-all lint test:unit test:type test:companion",
+    "uploadcdn": "bin/upload-to-cdn.sh",
+    "version": "./bin/sync-version-numbers",
     "watch:css": "onchange 'packages/**/*.scss' --initial --verbose -- npm run build:css",
-    "watch:js": "onchange 'packages/{@uppy/,}*/src/**/*.js' --initial --verbose -- npm run build:bundle",
+    "watch:js:bundle": "onchange 'packages/{@uppy/,}*/src/**/*.js' --initial --verbose -- npm run build:bundle",
     "watch:js:lib": "onchange 'packages/{@uppy/,}*/src/**/*.js' --initial --verbose -- npm run build:lib",
-    "watch": "npm-run-all --parallel watch:js watch:css",
-    "watch:fast": "npm-run-all --parallel watch:css web:preview",
-    "dev:browsersync": "browser-sync start --no-open --no-ghost-mode false --server examples/dev --port 3452 --serveStatic packages/uppy/dist --files \"examples/dev/bundle.js, packages/uppy/dist/uppy.min.css, packages/uppy/lib/**/*\"",
-    "dev:js": "cd examples/dev && npm run watch",
-    "dev": "npm-run-all --parallel start:companion dev:js watch:css watch:js:lib dev:browsersync",
-    "dev:no-companion": "npm-run-all --parallel dev:js watch:css watch:js:lib dev:browsersync",
-    "web:build": "cd website && node update.js && ./node_modules/.bin/hexo generate --silent && node build-examples.js",
-    "web:clean": "cd website && ./node_modules/.bin/hexo clean",
-    "web:deploy": "npm-run-all web:install web:disc web:build && ./bin/web-deploy",
-    "web:disc": "node ./bin/disc.js",
+    "watch": "npm-run-all --parallel watch:*",
+    "web:build-examples": "cd website && node build-examples.js",
+    "web:build": "npm-run-all web:inject-bundles-misc web:generate web:build-examples web:inject-frontpagecodesample",
+    "web:bundle-watch-inject": "onchange 'packages/uppy/dist/**/*.css' 'packages/uppy/dist/**/*.js' --initial --verbose -- npm run web:inject-bundles-misc",
+    "web:clean": "cd website && touch db.json && ./node_modules/.bin/hexo clean",
+    "web:deploy": "npm-run-all web:clean web:inject-disc web:build && ./bin/web-deploy",
+    "web:generate": "cd website && touch db.json && ./node_modules/.bin/hexo generate",
+    "web:inject-bundles-misc": "cd website && node inject.js",
+    "web:inject-disc": "node ./bin/disc.js",
+    "web:inject-frontpagecodesample": "npm run web:generate && cp -f website/public/frontpage-code-sample.html website/themes/uppy/layout/partials/frontpage-code-sample.html && touch website/themes/uppy/layout/index.ejs",
     "web:install": "cd website && npm install",
-    "web:bundle:update:watch": "onchange 'packages/uppy/dist/**/*.css' 'packages/uppy/dist/**/*.js' --initial --verbose -- node website/update.js",
-    "web:examples:watch": "cd website && node build-examples.js watch",
-    "web:serve": "cd website && ./node_modules/.bin/hexo server",
-    "web:preview": "npm-run-all build:lib --parallel web:examples:watch web:bundle:update:watch web:serve",
-    "web:update:frontpage:code:sample": "cd website && ./node_modules/.bin/hexo generate && cp -f public/frontpage-code-sample.html ./themes/uppy/layout/partials/frontpage-code-sample.html",
-    "web": "npm-run-all web:clean web:build",
-    "uploadcdn": "bin/upload-to-cdn.sh",
-    "bootstrap": "lerna bootstrap",
-    "contributors": "githubcontrib --owner transloadit --repo uppy --cols 6 $([ \"${GITHUB_TOKEN:-}\" == \"\" ] && echo \"\" || echo \"--authToken ${GITHUB_TOKEN}\") --showlogin true --sortOrder desc",
-    "contributors:save": "replace-x -m '<!--contributors-->[\\s\\S]+<!--/contributors-->' \"<!--contributors-->\n## Contributors\n\n$(npm run --silent contributors)\n<!--/contributors-->\" README.md"
+    "web:start": "npm-run-all build:lib --parallel watch:css web:watch-examples web:bundle-watch-inject web:watch",
+    "web:watch-examples": "cd website && node build-examples.js watch",
+    "web:watch": "cd website && touch db.json &&./node_modules/.bin/hexo server"
   },
   "jest": {
     "automock": false,

+ 1 - 1
packages/@uppy/aws-s3-multipart/README.md

@@ -28,7 +28,7 @@ uppy.use(AwsS3Multipart, {
 $ npm install @uppy/aws-s3-multipart --save
 ```
 
-We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
+We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
 Alternatively, you can also use this plugin in a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. See the [main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
 

+ 4 - 4
packages/@uppy/aws-s3-multipart/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/aws-s3-multipart",
   "description": "Upload to Amazon S3 with Uppy and S3's Multipart upload strategy",
-  "version": "0.30.2",
+  "version": "0.30.3",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",
@@ -23,12 +23,12 @@
     "url": "git+https://github.com/transloadit/uppy.git"
   },
   "dependencies": {
-    "@uppy/companion-client": "^0.28.2",
-    "@uppy/utils": "^0.30.2",
+    "@uppy/companion-client": "0.28.3",
+    "@uppy/utils": "0.30.3",
     "resolve-url": "^0.2.1"
   },
   "devDependencies": {
-    "@uppy/core": "^0.30.2"
+    "@uppy/core": "0.30.3"
   },
   "peerDependencies": {
     "@uppy/core": "^0.30.0"

+ 10 - 19
packages/@uppy/aws-s3-multipart/src/index.js

@@ -1,5 +1,5 @@
 const { Plugin } = require('@uppy/core')
-const { Socket, RequestClient } = require('@uppy/companion-client')
+const { Socket, Provider, RequestClient } = require('@uppy/companion-client')
 const emitSocketProgress = require('@uppy/utils/lib/emitSocketProgress')
 const getSocketHost = require('@uppy/utils/lib/getSocketHost')
 const limitPromises = require('@uppy/utils/lib/limitPromises')
@@ -249,28 +249,19 @@ module.exports = class AwsS3Multipart extends Plugin {
 
       this.uppy.emit('upload-started', file)
 
-      fetch(file.remote.url, {
-        method: 'post',
-        credentials: 'include',
-        headers: {
-          'Accept': 'application/json',
-          'Content-Type': 'application/json'
-        },
-        body: JSON.stringify(Object.assign({}, file.remote.body, {
+      const Client = file.remote.providerOptions.provider ? Provider : RequestClient
+      const client = new Client(this.uppy, file.remote.providerOptions)
+      client.post(
+        file.remote.url,
+        Object.assign({}, file.remote.body, {
           protocol: 's3-multipart',
           size: file.data.size,
           metadata: file.meta
-        }))
-      })
-      .then((res) => {
-        if (res.status < 200 || res.status > 300) {
-          return reject(res.statusText)
-        }
-
-        return res.json().then((data) => {
-          this.uppy.setFileState(file.id, { serverToken: data.token })
-          return this.uppy.getFile(file.id)
         })
+      ).then((res) => {
+        this.uppy.setFileState(file.id, { serverToken: res.token })
+        file = this.uppy.getFile(file.id)
+        return file
       })
       .then((file) => {
         return this.connectToServerSocket(file)

+ 1 - 1
packages/@uppy/aws-s3/README.md

@@ -29,7 +29,7 @@ uppy.use(AwsS3, {
 $ npm install @uppy/aws-s3 --save
 ```
 
-We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
+We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
 Alternatively, you can also use this plugin in a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. See the [main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
 

+ 5 - 5
packages/@uppy/aws-s3/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/aws-s3",
   "description": "Upload to Amazon S3 with Uppy",
-  "version": "0.30.2",
+  "version": "0.30.3",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",
@@ -22,13 +22,13 @@
     "url": "git+https://github.com/transloadit/uppy.git"
   },
   "dependencies": {
-    "@uppy/companion-client": "^0.28.2",
-    "@uppy/utils": "^0.30.2",
-    "@uppy/xhr-upload": "^0.30.2",
+    "@uppy/companion-client": "0.28.3",
+    "@uppy/utils": "0.30.3",
+    "@uppy/xhr-upload": "0.30.3",
     "resolve-url": "^0.2.1"
   },
   "devDependencies": {
-    "@uppy/core": "^0.30.2"
+    "@uppy/core": "0.30.3"
   },
   "peerDependencies": {
     "@uppy/core": "^0.30.0"

+ 1 - 1
packages/@uppy/companion-client/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/companion-client",
   "description": "Client library for communication with Companion. Intended for use in Uppy plugins.",
-  "version": "0.28.2",
+  "version": "0.28.3",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",

+ 11 - 0
packages/@uppy/companion-client/src/AuthError.js

@@ -0,0 +1,11 @@
+'use strict'
+
+class AuthError extends Error {
+  constructor () {
+    super('Authorization required')
+    this.name = 'AuthError'
+    this.isAuthError = true
+  }
+}
+
+module.exports = AuthError

+ 28 - 19
packages/@uppy/companion-client/src/Provider.js

@@ -1,6 +1,7 @@
 'use strict'
 
 const RequestClient = require('./RequestClient')
+const tokenStorage = require('./tokenStorage')
 
 const _getName = (id) => {
   return id.split('-').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(' ')
@@ -17,27 +18,32 @@ module.exports = class Provider extends RequestClient {
     this.tokenKey = `companion-${this.pluginId}-auth-token`
   }
 
-  get defaultHeaders () {
-    return Object.assign({}, super.defaultHeaders, {'uppy-auth-token': this.getAuthToken()})
+  headers () {
+    return new Promise((resolve, reject) => {
+      super.headers().then((headers) => {
+        this.getAuthToken().then((token) => {
+          resolve(Object.assign({}, headers, { 'uppy-auth-token': token }))
+        })
+      }).catch(reject)
+    })
+  }
+
+  onReceiveResponse (response) {
+    response = super.onReceiveResponse(response)
+    const authenticated = response.status !== 401
+    this.uppy.getPlugin(this.pluginId).setPluginState({ authenticated })
+    return response
   }
 
   // @todo(i.olarewaju) consider whether or not this method should be exposed
   setAuthToken (token) {
-    // @todo(i.olarewaju) add fallback for OOM storage
-    this.uppy.getPlugin(this.pluginId).storage.setItem(this.tokenKey, token)
+    return this.uppy.getPlugin(this.pluginId).storage.setItem(this.tokenKey, token)
   }
 
   getAuthToken () {
     return this.uppy.getPlugin(this.pluginId).storage.getItem(this.tokenKey)
   }
 
-  checkAuth () {
-    return this.get(`${this.id}/authorized`)
-      .then((payload) => {
-        return payload.authenticated
-      })
-  }
-
   authUrl () {
     return `${this.hostname}/${this.id}/connect`
   }
@@ -51,11 +57,14 @@ module.exports = class Provider extends RequestClient {
   }
 
   logout (redirect = location.href) {
-    return this.get(`${this.id}/logout?redirect=${redirect}`)
-      .then((res) => {
-        this.storage.removeItem(this.tokenKey)
-        return res
-      })
+    return new Promise((resolve, reject) => {
+      this.get(`${this.id}/logout?redirect=${redirect}`)
+        .then((res) => {
+          this.uppy.getPlugin(this.pluginId).storage.removeItem(this.tokenKey)
+            .then(() => resolve(res))
+            .catch(reject)
+        }).catch(reject)
+    })
   }
 
   static initPlugin (plugin, opts, defaultOpts) {
@@ -74,13 +83,13 @@ module.exports = class Provider extends RequestClient {
       plugin.opts.serverPattern = pattern
     } else {
       // does not start with https://
-      if (/^(?!https?:\/\/).*$/.test(opts.serverUrl)) {
-        plugin.opts.serverPattern = `${location.protocol}//${opts.serverUrl.replace(/^\/\//, '')}`
+      if (/^(?!https?:\/\/).*$/i.test(opts.serverUrl)) {
+        plugin.opts.serverPattern = `https://${opts.serverUrl.replace(/^\/\//, '')}`
       } else {
         plugin.opts.serverPattern = opts.serverUrl
       }
     }
 
-    plugin.storage = plugin.opts.storage || localStorage
+    plugin.storage = plugin.opts.storage || tokenStorage
   }
 }

+ 72 - 41
packages/@uppy/companion-client/src/RequestClient.js

@@ -1,5 +1,7 @@
 'use strict'
 
+const AuthError = require('./AuthError')
+
 // Remove the trailing slash so we can always safely append /xyz.
 function stripSlash (url) {
   return url.replace(/\/$/, '')
@@ -25,8 +27,18 @@ module.exports = class RequestClient {
     }
   }
 
-  get headers () {
-    return Object.assign({}, this.defaultHeaders, this.opts.serverHeaders || {})
+  headers () {
+    return Promise.resolve(Object.assign({}, this.defaultHeaders, this.opts.serverHeaders || {}))
+  }
+
+  _getPostResponseFunc (skip) {
+    return (response) => {
+      if (!skip) {
+        return this.onReceiveResponse(response)
+      }
+
+      return response
+    }
   }
 
   onReceiveResponse (response) {
@@ -52,51 +64,70 @@ module.exports = class RequestClient {
     return `${this.hostname}/${url}`
   }
 
-  get (path) {
-    return fetch(this._getUrl(path), {
-      method: 'get',
-      headers: this.headers,
-      credentials: 'same-origin'
-    })
-      // @todo validate response status before calling json
-      .then(this.onReceiveResponse)
-      .then((res) => res.json())
-      .catch((err) => {
-        throw new Error(`Could not get ${this._getUrl(path)}. ${err}`)
-      })
+  _json (res) {
+    if (res.status === 401) {
+      throw new AuthError()
+    }
+
+    if (res.status < 200 || res.status > 300) {
+      throw new Error(`Failed request to ${res.url}. ${res.statusText}`)
+    }
+    return res.json()
   }
 
-  post (path, data) {
-    return fetch(this._getUrl(path), {
-      method: 'post',
-      headers: this.headers,
-      credentials: 'same-origin',
-      body: JSON.stringify(data)
-    })
-      .then(this.onReceiveResponse)
-      .then((res) => {
-        if (res.status < 200 || res.status > 300) {
-          throw new Error(`Could not post ${this._getUrl(path)}. ${res.statusText}`)
-        }
-        return res.json()
-      })
-      .catch((err) => {
-        throw new Error(`Could not post ${this._getUrl(path)}. ${err}`)
+  get (path, skipPostResponse) {
+    return new Promise((resolve, reject) => {
+      this.headers().then((headers) => {
+        fetch(this._getUrl(path), {
+          method: 'get',
+          headers: headers,
+          credentials: 'same-origin'
+        })
+          .then(this._getPostResponseFunc(skipPostResponse))
+          .then((res) => this._json(res).then(resolve))
+          .catch((err) => {
+            err = err.isAuthError ? err : new Error(`Could not get ${this._getUrl(path)}. ${err}`)
+            reject(err)
+          })
       })
+    })
   }
 
-  delete (path, data) {
-    return fetch(`${this.hostname}/${path}`, {
-      method: 'delete',
-      headers: this.headers,
-      credentials: 'same-origin',
-      body: data ? JSON.stringify(data) : null
+  post (path, data, skipPostResponse) {
+    return new Promise((resolve, reject) => {
+      this.headers().then((headers) => {
+        fetch(this._getUrl(path), {
+          method: 'post',
+          headers: headers,
+          credentials: 'same-origin',
+          body: JSON.stringify(data)
+        })
+          .then(this._getPostResponseFunc(skipPostResponse))
+          .then((res) => this._json(res).then(resolve))
+          .catch((err) => {
+            err = err.isAuthError ? err : new Error(`Could not post ${this._getUrl(path)}. ${err}`)
+            reject(err)
+          })
+      })
     })
-      .then(this.onReceiveResponse)
-      // @todo validate response status before calling json
-      .then((res) => res.json())
-      .catch((err) => {
-        throw new Error(`Could not delete ${this._getUrl(path)}. ${err}`)
+  }
+
+  delete (path, data, skipPostResponse) {
+    return new Promise((resolve, reject) => {
+      this.headers().then((headers) => {
+        fetch(`${this.hostname}/${path}`, {
+          method: 'delete',
+          headers: headers,
+          credentials: 'same-origin',
+          body: data ? JSON.stringify(data) : null
+        })
+          .then(this._getPostResponseFunc(skipPostResponse))
+          .then((res) => this._json(res).then(resolve))
+          .catch((err) => {
+            err = err.isAuthError ? err : new Error(`Could not delete ${this._getUrl(path)}. ${err}`)
+            reject(err)
+          })
       })
+    })
   }
 }

+ 21 - 0
packages/@uppy/companion-client/src/tokenStorage.js

@@ -0,0 +1,21 @@
+'use strict'
+/**
+ * This module serves as an Async wrapper for LocalStorage
+ */
+module.exports.setItem = (key, value) => {
+  return new Promise((resolve) => {
+    localStorage.setItem(key, value)
+    resolve()
+  })
+}
+
+module.exports.getItem = (key) => {
+  return Promise.resolve(localStorage.getItem(key))
+}
+
+module.exports.removeItem = (key) => {
+  return new Promise((resolve) => {
+    localStorage.removeItem(key)
+    resolve()
+  })
+}

+ 33 - 0
packages/@uppy/companion/README.md

@@ -15,6 +15,8 @@ Instagram, etc. **Companion is not a target to upload files to**. For this, use
 npm install @uppy/companion
 ```
 
+If you don't have a Node.js project with a `package.json` you might want to install/run Companion globally like so: `[sudo] npm install -g @uppy/companion@0.30.0`.
+
 ## Usage
 
 companion may either be used as pluggable express app, which you plug to your already existing server, or it may simply be run as a standalone server:
@@ -95,5 +97,36 @@ When you are all set install the dependencies and deploy your function:
 npm install && sls deploy
 ```
 
+### Deploy to heroku
+
+Companion can also be deployed to [Heroku](https://www.heroku.com)
+```
+mkdir uppy-companion && cd uppy-companion
+
+git init
+
+echo 'export COMPANION_PORT=$PORT' > .profile
+echo 'node_modules' > .gitignore
+echo '{
+  "name": "uppy-companion",
+  "version": "1.0.0",
+  "scripts": {
+    "start": "companion"
+  },
+  "dependencies": {
+    "@uppy/companion": "^0.17.0"
+  }
+}' > package.json
+
+npm i
+
+git add . && git commit -am 'first commit'
+
+heroku create
+
+git push heroku master
+```
+Make sure you set the required [environment variables](https://uppy.io/docs/companion/#Configure-Standalone).
+
 
 See [full documentation](https://uppy.io/docs/companion/)

+ 2 - 7
packages/@uppy/companion/infra/kube/companion/companion-kube.yaml

@@ -48,14 +48,9 @@ spec:
       containers:
       - image: docker.io/transloadit/companion:latest
         imagePullPolicy: Always
-        name: companion        
-        resources:
-          limits:
-            memory: 2Gi
-          requests:
-            memory: 2Gi
+        name: companion
         envFrom:
-        - configMapRef:
+        - secretRef:
             name: uppy-companion-env
         ports:
         - containerPort: 3020

+ 1 - 1
packages/@uppy/companion/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@uppy/companion",
-  "version": "0.17.2",
+  "version": "0.17.3",
   "description": "OAuth helper and remote fetcher for Uppy's (https://uppy.io) extensible file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Dropbox and Google Drive, S3 and more :dog:",
   "main": "lib/uppy.js",
   "types": "types/index.d.ts",

+ 11 - 0
packages/@uppy/companion/src/server/Uploader.js

@@ -52,6 +52,13 @@ class Uploader {
    * @returns {boolean}
    */
   validateOptions (options) {
+    // s3 uploads don't require upload destination
+    // validation, because the destination is determined
+    // by the server's s3 config
+    if (options.protocol === 's3-multipart') {
+      return true
+    }
+
     if (!options.endpoint && !options.uploadUrl) {
       this._errRespMessage = 'No destination specified'
       return false
@@ -74,6 +81,10 @@ class Uploader {
     })
   }
 
+  hasError () {
+    return this._errRespMessage != null
+  }
+
   /**
    * returns a substring of the token
    */

+ 12 - 2
packages/@uppy/companion/src/server/controllers/get.js

@@ -2,7 +2,7 @@ const Uploader = require('../Uploader')
 const redis = require('../redis')
 const logger = require('../logger')
 
-function get (req, res) {
+function get (req, res, next) {
   const providerName = req.params.providerName
   const id = req.params.id
   const body = req.body
@@ -11,7 +11,11 @@ function get (req, res) {
   const { providerOptions } = req.uppy.options
 
   // get the file size before proceeding
-  provider.size({ id, token }, (size) => {
+  provider.size({ id, token }, (err, size) => {
+    if (err) {
+      return err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+
     if (!size) {
       logger.error('unable to determine file size', 'controller.get.provider.size')
       return res.status(400).json({error: 'unable to determine file size'})
@@ -35,6 +39,12 @@ function get (req, res) {
       headers: body.headers
     })
 
+    if (uploader.hasError()) {
+      const response = uploader.getResponse()
+      res.status(response.status).json(response.body)
+      return
+    }
+
     // wait till the client has connected to the socket, before starting
     // the download, so that the client can receive all download/upload progress.
     logger.debug('Waiting for socket connection before beginning remote download.')

+ 4 - 1
packages/@uppy/companion/src/server/controllers/list.js

@@ -3,7 +3,10 @@ function list ({ query, params, uppy }, res, next) {
   const token = uppy.providerTokens[providerName]
 
   uppy.provider.list({ uppy, token, directory: params.id, query }, (err, data) => {
-    return err ? next(err) : res.json(data)
+    if (err) {
+      return err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+    return res.json(data)
   })
 }
 

+ 2 - 6
packages/@uppy/companion/src/server/controllers/logout.js

@@ -9,13 +9,9 @@ function logout (req, res) {
   const session = req.session
   const providerName = req.params.providerName
 
-  if (req.uppy.providerTokens[providerName]) {
+  if (req.uppy.providerTokens && req.uppy.providerTokens[providerName]) {
     delete req.uppy.providerTokens[providerName]
-    tokenService.addToCookies(
-      res,
-      tokenService.generateToken(req.uppy.providerTokens, req.uppy.options.secret),
-      req.uppy.options
-    )
+    tokenService.removeFromCookies(res, req.uppy.options, req.uppy.provider.authProviderName)
   }
 
   if (session.grant) {

+ 1 - 1
packages/@uppy/companion/src/server/controllers/send-token.js

@@ -16,7 +16,7 @@ const oAuthState = require('../helpers/oauth-state')
 module.exports = function sendToken (req, res, next) {
   const uppyAuthToken = req.uppy.authToken
   // add the token to cookies for thumbnail/image requests
-  tokenService.addToCookies(res, uppyAuthToken, req.uppy.options)
+  tokenService.addToCookies(res, uppyAuthToken, req.uppy.options, req.uppy.provider.authProvider)
 
   const state = (req.session.grant || {}).state
   if (state) {

+ 7 - 2
packages/@uppy/companion/src/server/controllers/thumbnail.js

@@ -3,13 +3,18 @@
  * @param {object} req
  * @param {object} res
  */
-function thumbnail (req, res) {
+function thumbnail (req, res, next) {
   const providerName = req.params.providerName
   const id = req.params.id
   const token = req.uppy.providerTokens[providerName]
   const provider = req.uppy.provider
 
-  provider.thumbnail({ id, token }, (response) => response ? response.pipe(res) : res.sendStatus(404))
+  provider.thumbnail({ id, token }, (err, response) => {
+    if (err) {
+      err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+    response ? response.pipe(res) : res.sendStatus(404)
+  })
 }
 
 module.exports = thumbnail

+ 8 - 0
packages/@uppy/companion/src/server/controllers/url.js

@@ -56,11 +56,18 @@ const get = (req, res) => {
         protocol: req.body.protocol,
         metadata: req.body.metadata,
         size: size,
+        fieldname: req.body.fieldname,
         pathPrefix: `${filePath}`,
         storage: redis.client(),
         headers: req.body.headers
       })
 
+      if (uploader.hasError()) {
+        const response = uploader.getResponse()
+        res.status(response.status).json(response.body)
+        return
+      }
+
       logger.debug('Waiting for socket connection before beginning remote download.')
       uploader.onSocketReady(() => {
         logger.debug('Socket connection received. Starting remote download.')
@@ -91,5 +98,6 @@ const downloadURL = (url, onDataChunk) => {
 
   request(opts)
     .on('data', onDataChunk)
+    .on('end', () => onDataChunk(null))
     .on('error', (err) => logger.error(err, 'controller.url.download.error'))
 }

+ 22 - 2
packages/@uppy/companion/src/server/helpers/jwt.js

@@ -29,8 +29,9 @@ module.exports.verifyToken = (token, secret) => {
  * @param {object} res
  * @param {string} token
  * @param {object=} uppyOptions
+ * @param {string} providerName
  */
-module.exports.addToCookies = (res, token, uppyOptions) => {
+module.exports.addToCookies = (res, token, uppyOptions, providerName) => {
   const cookieOptions = {
     maxAge: 1000 * 60 * 60 * 24 * 30, // would expire after 30 days
     httpOnly: true
@@ -40,5 +41,24 @@ module.exports.addToCookies = (res, token, uppyOptions) => {
     cookieOptions.domain = uppyOptions.cookieDomain
   }
   // send signed token to client.
-  res.cookie('uppyAuthToken', token, cookieOptions)
+  res.cookie(`uppyAuthToken--${providerName}`, token, cookieOptions)
+}
+
+/**
+ *
+ * @param {object} res
+ * @param {object=} uppyOptions
+ * @param {string} providerName
+ */
+module.exports.removeFromCookies = (res, uppyOptions, providerName) => {
+  const cookieOptions = {
+    maxAge: 1000 * 60 * 60 * 24 * 30, // would expire after 30 days
+    httpOnly: true
+  }
+
+  if (uppyOptions.cookieDomain) {
+    cookieOptions.domain = uppyOptions.cookieDomain
+  }
+
+  res.clearCookie(`uppyAuthToken--${providerName}`, cookieOptions)
 }

+ 1 - 1
packages/@uppy/companion/src/server/helpers/utils.js

@@ -38,7 +38,7 @@ exports.jsonStringify = (data) => {
  * @param {string} text
  */
 exports.sanitizeHtml = (text) => {
-  return text.replace(/<\/?[^>]+(>|$)/g, '')
+  return text ? text.replace(/<\/?[^>]+(>|$)/g, '') : text
 }
 
 /**

+ 3 - 1
packages/@uppy/companion/src/server/logger.js

@@ -45,5 +45,7 @@ exports.debug = (msg, tag) => {
 const log = (msg, tag, level) => {
   // @TODO add some colors based on log level
   const time = new Date().toISOString()
-  console.log(`uppy: ${time} [${level}] ${tag || ''} ${msg}`)
+  // exclude msg from template string so values such as error objects
+  // can be well formatted
+  console.log(`uppy: ${time} [${level}] ${tag || ''}`, msg)
 }

+ 1 - 1
packages/@uppy/companion/src/server/middlewares.js

@@ -38,6 +38,6 @@ exports.gentleVerifyToken = (req, res, next) => {
 }
 
 exports.cookieAuthToken = (req, res, next) => {
-  req.uppy.authToken = req.cookies.uppyAuthToken
+  req.uppy.authToken = req.cookies[`uppyAuthToken--${req.uppy.provider.authProvider}`]
   return next()
 }

+ 6 - 0
packages/@uppy/companion/src/server/provider/drive/adapter.js

@@ -22,6 +22,12 @@ exports.getItemIcon = (item) => {
   if (item.kind === 'drive#teamDrive') {
     return item.backgroundImageLink + '=w16-h16-n'
   }
+
+  if (item.thumbnailLink) {
+    const smallerThumbnailLink = item.thumbnailLink.replace('s220', 's40')
+    return smallerThumbnailLink
+  }
+
   return item.iconLink
 }
 

+ 22 - 10
packages/@uppy/companion/src/server/provider/drive/index.js

@@ -3,6 +3,7 @@ const request = require('request')
 const purest = require('purest')({ request })
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
 const DRIVE_FILE_FIELDS = 'kind,id,name,mimeType,ownedByMe,permissions(role,emailAddress),size,modifiedTime,iconLink,thumbnailLink,teamDriveId'
 const DRIVE_FILES_FIELDS = `kind,nextPageToken,incompleteSearch,files(${DRIVE_FILE_FIELDS})`
 const TEAM_DRIVE_FIELDS = 'teamDrives(kind,id,name,backgroundImageLink)'
@@ -30,10 +31,10 @@ class Drive {
     let listResponse
     let reqErr
     const finishReq = () => {
-      if (reqErr) {
-        done(reqErr)
-      } else if (listResponse.statusCode !== 200) {
-        done(new Error(`request to ${this.authProvider} returned ${listResponse.statusCode}`))
+      if (reqErr || listResponse.statusCode !== 200) {
+        const err = this._error(reqErr, listResponse)
+        logger.error(err, 'provider.drive.list.error')
+        done(err)
       } else {
         done(null, this.adaptData(listResponse.body, teamDrives ? teamDrives.body : null, options.uppy))
       }
@@ -110,21 +111,24 @@ class Drive {
 
   thumbnail ({id, token}, done) {
     return this.stats({id, token}, (err, resp, body) => {
-      if (err) {
+      if (err || resp.statusCode !== 200) {
+        err = this._error(err, resp)
         logger.error(err, 'provider.drive.thumbnail.error')
-        return done(null)
+        return done(err)
       }
-      done(body.thumbnailLink ? request(body.thumbnailLink) : null)
+
+      done(null, body.thumbnailLink ? request(body.thumbnailLink) : null)
     })
   }
 
   size ({id, token}, done) {
     return this.stats({ id, token }, (err, resp, body) => {
-      if (err) {
+      if (err || resp.statusCode !== 200) {
+        err = this._error(err, resp)
         logger.error(err, 'provider.drive.size.error')
-        return done(null)
+        return done(err)
       }
-      done(parseInt(body.size))
+      done(null, parseInt(body.size))
     })
   }
 
@@ -152,6 +156,14 @@ class Drive {
 
     return data
   }
+
+  _error (err, resp) {
+    if (resp) {
+      const errMsg = `request to ${this.authProvider} returned ${resp.statusCode}`
+      return resp.statusCode === 401 ? new AuthError() : new Error(errMsg)
+    }
+    return err
+  }
 }
 
 module.exports = Drive

+ 41 - 11
packages/@uppy/companion/src/server/provider/dropbox/index.js

@@ -2,6 +2,20 @@ const request = require('request')
 const purest = require('purest')({ request })
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
+
+// From https://www.dropbox.com/developers/reference/json-encoding:
+//
+// This function is simple and has OK performance compared to more
+// complicated ones: http://jsperf.com/json-escape-unicode/4
+const charsToEncode = /[\u007f-\uffff]/g
+function httpHeaderSafeJson (v) {
+  return JSON.stringify(v).replace(charsToEncode,
+    function (c) {
+      return '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4)
+    }
+  )
+}
 
 class DropBox {
   constructor (options) {
@@ -35,10 +49,10 @@ class DropBox {
     let stats
     let reqErr
     const finishReq = () => {
-      if (reqErr) {
-        done(reqErr)
-      } else if (stats.statusCode !== 200) {
-        done(new Error(`request to ${this.authProvider} returned ${stats.statusCode}`))
+      if (reqErr || stats.statusCode !== 200) {
+        const err = this._error(reqErr, stats)
+        logger.error(err, 'provider.dropbox.list.error')
+        done(err)
       } else {
         stats.body.user_email = userInfo.body.email
         done(null, this.adaptData(stats.body, options.uppy))
@@ -83,7 +97,7 @@ class DropBox {
       .options({
         version: '2',
         headers: {
-          'Dropbox-API-Arg': JSON.stringify({path: `${id}`})
+          'Dropbox-API-Arg': httpHeaderSafeJson({path: `${id}`})
         }
       })
       .auth(token)
@@ -101,12 +115,19 @@ class DropBox {
       .options({
         version: '2',
         headers: {
-          'Dropbox-API-Arg': JSON.stringify({path: `${id}`})
+          'Dropbox-API-Arg': httpHeaderSafeJson({path: `${id}`})
         }
       })
       .auth(token)
       .request()
-      .on('response', done)
+      .on('response', (resp) => {
+        if (resp.statusCode !== 200) {
+          const err = this._error(null, resp)
+          logger.error(err, 'provider.dropbox.thumbnail.error')
+          return done(err)
+        }
+        done(null, resp)
+      })
       .on('error', (err) => {
         logger.error(err, 'provider.dropbox.thumbnail.error')
       })
@@ -122,12 +143,12 @@ class DropBox {
         include_media_info: true
       })
       .request((err, resp, body) => {
-        if (err) {
+        if (err || resp.statusCode !== 200) {
+          err = this._error(err, resp)
           logger.error(err, 'provider.dropbox.size.error')
-          return done(null)
+          return done(err)
         }
-
-        done(body.size)
+        done(null, parseInt(body.size))
       })
   }
 
@@ -151,6 +172,15 @@ class DropBox {
 
     return data
   }
+
+  _error (err, resp) {
+    if (resp) {
+      const errMsg = `request to ${this.authProvider} returned ${resp.statusCode}`
+      return resp.statusCode === 401 ? new AuthError() : new Error(errMsg)
+    }
+
+    return err
+  }
 }
 
 module.exports = DropBox

+ 13 - 0
packages/@uppy/companion/src/server/provider/error.js

@@ -0,0 +1,13 @@
+/**
+ * AuthError is error returned when an adapter encounters
+ * an authorization error while communication with its corresponding provider
+ */
+class AuthError extends Error {
+  constructor () {
+    super('invalid access token detected by Provider')
+    this.name = 'AuthError'
+    this.isAuthError = true
+  }
+}
+
+module.exports = AuthError

+ 34 - 9
packages/@uppy/companion/src/server/provider/instagram/index.js

@@ -3,6 +3,7 @@ const purest = require('purest')({ request })
 const utils = require('../../helpers/utils')
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
 
 class Instagram {
   constructor (options) {
@@ -21,10 +22,10 @@ class Instagram {
       .qs(qs)
       .auth(token)
       .request((err, resp, body) => {
-        if (err) {
-          done(err)
-        } else if (resp.statusCode !== 200) {
-          done(new Error(`request to ${this.authProvider} returned ${resp.statusCode}`))
+        if (err || resp.statusCode !== 200) {
+          err = this._error(err, resp)
+          logger.error(err, 'provider.instagram.list.error')
+          return done(err)
         } else {
           done(null, this.adaptData(body))
         }
@@ -67,10 +68,21 @@ class Instagram {
       .get(`media/${id}`)
       .auth(token)
       .request((err, resp, body) => {
-        if (err) return logger.error(err, 'provider.instagram.thumbnail.error')
+        if (err) {
+          err = this._error(err, resp)
+          logger.error(err, 'provider.instagram.thumbnail.error')
+          return done(err)
+        }
 
         request(body.data.images.thumbnail.url)
-          .on('response', done)
+          .on('response', (resp) => {
+            if (resp.statusCode !== 200) {
+              err = this._error(null, resp)
+              logger.error(err, 'provider.instagram.thumbnail.error')
+              return done(err)
+            }
+            done(null, resp)
+          })
           .on('error', (err) => {
             logger.error(err, 'provider.instagram.thumbnail.error')
           })
@@ -82,13 +94,14 @@ class Instagram {
       .get(`media/${id}`)
       .auth(token)
       .request((err, resp, body) => {
-        if (err) {
+        if (err || resp.statusCode !== 200) {
+          err = this._error(err, resp)
           logger.error(err, 'provider.instagram.size.error')
-          return done()
+          return done(err)
         }
 
         utils.getURLMeta(this._getMediaUrl(body, query.carousel_id))
-          .then(({ size }) => done(size))
+          .then(({ size }) => done(null, size))
           .catch((err) => {
             logger.error(err, 'provider.instagram.size.error')
             done()
@@ -115,6 +128,18 @@ class Instagram {
     data.nextPagePath = adapter.getNextPagePath(items)
     return data
   }
+
+  _error (err, resp) {
+    if (resp) {
+      if (resp.statusCode === 400 && resp.body && resp.body.meta.error_type === 'OAuthAccessTokenException') {
+        return new AuthError()
+      }
+
+      return new Error(`request to ${this.authProvider} returned ${resp.statusCode}`)
+    }
+
+    return err
+  }
 }
 
 module.exports = Instagram

+ 1 - 1
packages/@uppy/companion/src/standalone/helper.js

@@ -174,7 +174,7 @@ exports.buildHelpfulStartupMessage = (uppyOptions) => {
       providerName = 'drive'
     }
 
-    callbackURLs.push(buildURL(`/${providerName}/callback`, true))
+    callbackURLs.push(buildURL(`/connect/${providerName}/callback`, true))
   })
 
   return stripIndent`

+ 1 - 1
packages/@uppy/companion/test/__tests__/companion.js

@@ -80,7 +80,7 @@ describe('test authentication', () => {
       .get(`/drive/send-token?uppyAuthToken=${token}`)
       .expect(200)
       .expect((res) => {
-        const authToken = res.header['set-cookie'][0].split(';')[0].split('uppyAuthToken=')[1]
+        const authToken = res.header['set-cookie'][0].split(';')[0].split('uppyAuthToken--google=')[1]
         expect(authToken).toEqual(token)
         // see mock ../../src/server/helpers/oauth-state above for http://localhost:3020
         const body = `

+ 1 - 1
packages/@uppy/core/README.md

@@ -30,7 +30,7 @@ uppy.use(SomePlugin)
 $ npm install @uppy/core --save
 ```
 
-We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
+We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
 Alternatively, you can also use this plugin in a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. See the [main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
 

+ 3 - 3
packages/@uppy/core/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/core",
   "description": "Core module for the 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": "0.30.2",
+  "version": "0.30.3",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",
@@ -20,8 +20,8 @@
     "url": "git+https://github.com/transloadit/uppy.git"
   },
   "dependencies": {
-    "@uppy/store-default": "^0.28.2",
-    "@uppy/utils": "^0.30.2",
+    "@uppy/store-default": "0.28.3",
+    "@uppy/utils": "0.30.3",
     "cuid": "^2.1.1",
     "lodash.throttle": "^4.1.1",
     "mime-match": "^1.0.2",

+ 19 - 39
packages/@uppy/core/src/_common.scss

@@ -8,6 +8,8 @@
   line-height: 1;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
+  text-align: left;
+  position: relative;
 }
 
 .uppy-Root *, .uppy-Root *:before, .uppy-Root *:after {
@@ -21,6 +23,13 @@
 .uppy-Root *:focus {
   outline: $size-focus-outline solid $color-cornflower-blue; /* no !important */
   outline-offset: $size-focus-offset; /* no !important */
+
+  // outline: none;
+  // box-shadow: inset 0 0 0 2px rgba($color-cornflower-blue, 0.5);
+}
+
+.uppy-Root [hidden] {
+  display: none;
 }
 
 // https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
@@ -41,72 +50,46 @@
 // Utilities
 
 .uppy-u-reset {
-  // @include reset-button;
-  animation: none 0s ease 0s 1 normal none running;
+  -webkit-appearance: none;
+  line-height: 1;
+  padding: 0;
+  margin: 0;
+  border: 0;
+  color: inherit;
   backface-visibility: visible;
-  background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;
+  background: none;
   border: medium none currentColor;
   border-collapse: separate;
   border-image: none;
   border-radius: 0;
   border-spacing: 0;
-  bottom: auto;
   box-shadow: none;
-  // box-sizing: content-box;
-  caption-side: top;
   clear: none;
-  clip: auto;
-  color: #000;
-  columns: auto;
-  column-count: auto;
-  column-fill: balance;
-  column-gap: normal;
-  column-rule: medium none currentColor;
-  column-span: 1;
-  column-width: auto;
-  content: normal;
-  counter-increment: none;
-  counter-reset: none;
   cursor: auto;
-  // direction: ltr;
   display: inline;
   empty-cells: show;
   float: none;
   font-family: inherit;
-  font-size: medium;
+  font-size: inherit;
   font-style: normal;
   font-variant: normal;
   font-weight: normal;
   font-stretch: normal;
-  line-height: normal;
-  height: auto;
   hyphens: none;
   left: auto;
   letter-spacing: normal;
-  list-style: disc outside none;
+  list-style: none;
   margin: 0;
   max-height: none;
   max-width: none;
   min-height: 0;
   min-width: 0;
   opacity: 1;
-  orphans: 2;
   outline: medium none invert;
   overflow: visible;
   overflow-x: visible;
   overflow-y: visible;
-  padding: 0;
-  page-break-after: auto;
-  page-break-before: auto;
-  page-break-inside: auto;
-  perspective: none;
-  perspective-origin: 50% 50%;
-  position: static;
-  right: auto;
-  tab-size: 8;
-  table-layout: auto;
   text-align: left;
-  text-align-last: auto;
   text-decoration: none;
   text-indent: 0;
   text-shadow: none;
@@ -120,11 +103,7 @@
   vertical-align: baseline;
   visibility: visible;
   white-space: normal;
-  widows: 2;
-  width: auto;
-  word-spacing: normal;
   z-index: auto;
-  // all: initial;
 }
 
 // Inputs
@@ -135,6 +114,7 @@
   font-size: 13px;
   line-height: 1.5;
   padding: 6px 8px;
+  background-color: $color-white;
 }
 
   .uppy-size--md .uppy-c-textInput {

+ 7 - 7
packages/@uppy/core/src/index.js

@@ -34,8 +34,9 @@ class Uppy {
           1: 'You have to select at least %{smart_count} files'
         },
         exceedsSize: 'This file exceeds maximum allowed size of',
-        youCanOnlyUploadFileTypes: 'You can only upload:',
+        youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
         companionError: 'Connection with Companion failed',
+        companionAuthError: 'Authorization required',
         failedToUpload: 'Failed to upload %{file}',
         noInternetConnection: 'No Internet connection',
         connectedToInternet: 'Connected to the Internet',
@@ -343,7 +344,7 @@ class Uppy {
     }
 
     if (allowedFileTypes) {
-      const isCorrectFileType = allowedFileTypes.filter((type) => {
+      const isCorrectFileType = allowedFileTypes.some((type) => {
         // if (!file.type) return false
 
         // is this is a mime-type
@@ -354,15 +355,14 @@ class Uppy {
 
         // otherwise this is likely an extension
         if (type[0] === '.') {
-          if (file.extension === type.substr(1)) {
-            return file.extension
-          }
+          return file.extension.toLowerCase() === type.substr(1).toLowerCase()
         }
-      }).length > 0
+        return false
+      })
 
       if (!isCorrectFileType) {
         const allowedFileTypesString = allowedFileTypes.join(', ')
-        throw new Error(`${this.i18n('youCanOnlyUploadFileTypes')} ${allowedFileTypesString}`)
+        throw new Error(this.i18n('youCanOnlyUploadFileTypes', { types: allowedFileTypesString }))
       }
     }
 

+ 7 - 0
packages/@uppy/core/src/index.test.js

@@ -1179,6 +1179,13 @@ describe('src/Core', () => {
         expect(err).toMatchObject(new Error('You can only upload: .gif, .jpg, .jpeg'))
         expect(core.getState().info.message).toEqual('You can only upload: .gif, .jpg, .jpeg')
       }
+
+      expect(() => core.addFile({
+        source: 'jest',
+        name: 'foo2.JPG',
+        type: '',
+        data: new File([sampleImage], { type: 'image/jpeg' })
+      }).not.toThrow())
     })
 
     it('should enforce the maxFileSize rule', () => {

+ 1 - 1
packages/@uppy/dashboard/README.md

@@ -37,7 +37,7 @@ uppy.use(Dashboard, {
 $ npm install @uppy/dashboard --save
 ```
 
-We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
+We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
 Alternatively, you can also use this plugin in a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. See the [main Uppy documentation](https://uppy.io/docs/#Installation) for instructions.
 

+ 8 - 8
packages/@uppy/dashboard/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/dashboard",
   "description": "Universal UI plugin for Uppy.",
-  "version": "0.30.2",
+  "version": "0.30.3",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",
@@ -22,11 +22,11 @@
     "url": "git+https://github.com/transloadit/uppy.git"
   },
   "dependencies": {
-    "@uppy/informer": "^0.30.2",
-    "@uppy/provider-views": "^0.30.2",
-    "@uppy/status-bar": "^0.30.2",
-    "@uppy/thumbnail-generator": "^0.30.2",
-    "@uppy/utils": "^0.30.2",
+    "@uppy/informer": "0.30.3",
+    "@uppy/provider-views": "0.30.3",
+    "@uppy/status-bar": "0.30.3",
+    "@uppy/thumbnail-generator": "0.30.3",
+    "@uppy/utils": "0.30.3",
     "classnames": "^2.2.6",
     "cuid": "^2.1.1",
     "drag-drop": "2.13.3",
@@ -37,8 +37,8 @@
     "resize-observer-polyfill": "^1.5.0"
   },
   "devDependencies": {
-    "@uppy/core": "^0.30.2",
-    "@uppy/google-drive": "^0.30.2"
+    "@uppy/core": "0.30.3",
+    "@uppy/google-drive": "0.30.3"
   },
   "peerDependencies": {
     "@uppy/core": "^0.30.0"

+ 4 - 4
packages/@uppy/dashboard/src/components/AddFiles.js

@@ -22,7 +22,7 @@ class AddFiles extends Component {
 
     if (!hasAcquirers) {
       return (
-        <div class="uppy-DashboarAddFiles">
+        <div class="uppy-DashboardAddFiles">
           <div class="uppy-DashboardTabs">
             <ActionBrowseTagline
               acquirers={this.props.acquirers}
@@ -33,7 +33,7 @@ class AddFiles extends Component {
               maxNumberOfFiles={this.props.maxNumberOfFiles}
             />
           </div>
-          <div class="uppy-DashboarAddFiles-info">
+          <div class="uppy-DashboardAddFiles-info">
             { this.props.note && <div class="uppy-Dashboard-note">{this.props.note}</div> }
             { this.props.proudlyDisplayPoweredByUppy && poweredByUppy(this.props) }
           </div>
@@ -45,7 +45,7 @@ class AddFiles extends Component {
     // because Uppy will be handling the upload and so we can select same file
     // after removing — otherwise browser thinks it’s already selected
     return (
-      <div class="uppy-DashboarAddFiles">
+      <div class="uppy-DashboardAddFiles">
         <div class="uppy-DashboardTabs">
           <ActionBrowseTagline
             acquirers={this.props.acquirers}
@@ -93,7 +93,7 @@ class AddFiles extends Component {
             })}
           </div>
         </div>
-        <div class="uppy-DashboarAddFiles-info">
+        <div class="uppy-DashboardAddFiles-info">
           { this.props.note && <div class="uppy-Dashboard-note">{this.props.note}</div> }
           { this.props.proudlyDisplayPoweredByUppy && poweredByUppy(this.props) }
         </div>

+ 13 - 8
packages/@uppy/dashboard/src/components/Dashboard.js

@@ -35,7 +35,8 @@ module.exports = function Dashboard (props) {
     { 'uppy-Dashboard--modal': !props.inline },
     { 'uppy-size--md': props.containerWidth > 576 },
     { 'uppy-size--lg': props.containerWidth > 700 },
-    { 'uppy-Dashboard--isAddFilesPanelVisible': props.showAddFilesPanel }
+    { 'uppy-Dashboard--isAddFilesPanelVisible': props.showAddFilesPanel },
+    { 'uppy-Dashboard--isInnerWrapVisible': props.areInsidesReadyToBeVisible }
   )
 
   return (
@@ -53,13 +54,17 @@ module.exports = function Dashboard (props) {
           width: props.inline && props.width ? props.width : '',
           height: props.inline && props.height ? props.height : ''
         }}>
-        <button class="uppy-Dashboard-close"
-          type="button"
-          aria-label={props.i18n('closeModal')}
-          title={props.i18n('closeModal')}
-          onclick={props.closeModal}>
-          <span aria-hidden="true">&times;</span>
-        </button>
+
+        {!props.inline
+          ? <button class="uppy-u-reset uppy-Dashboard-close"
+            type="button"
+            aria-label={props.i18n('closeModal')}
+            title={props.i18n('closeModal')}
+            onclick={props.closeModal}>
+            <span aria-hidden="true">&times;</span>
+          </button>
+            : null
+          }
 
         <div class="uppy-Dashboard-innerWrap">
           { (!noFiles && props.showSelectedFiles) && <PanelTopBar {...props} /> }

+ 1 - 1
packages/@uppy/dashboard/src/components/FileCard.js

@@ -42,7 +42,7 @@ class FileCard extends Component {
     return metaFields.map((field, i) => {
       return <fieldset class="uppy-DashboardFileCard-fieldset">
         <label class="uppy-DashboardFileCard-label">{field.name}</label>
-        <input class="uppy-c-textInput uppy-DashboardFileCard-input"
+        <input class="uppy-u-reset uppy-c-textInput uppy-DashboardFileCard-input"
           type="text"
           data-name={field.id}
           value={file.meta[field.id]}

+ 48 - 17
packages/@uppy/dashboard/src/index.js

@@ -472,6 +472,48 @@ module.exports = class Dashboard extends Plugin {
     })
   }
 
+  // _Why make insides of Dashboard invisible until first ResizeObserver event is emitted?
+  //  ResizeOberserver doesn't emit the first resize event fast enough, users can see the jump from one .uppy-size-- to another (e.g. in Safari)
+  // _Why not apply visibility property to .uppy-Dashboard-inner?
+  //  Because ideally, acc to specs, ResizeObserver should see invisible elements as of width 0. So even though applying invisibility to .uppy-Dashboard-inner works now, it may not work in the future.
+  startListeningToResize () {
+    // Watch for Dashboard container (`.uppy-Dashboard-inner`) resize
+    // and update containerWidth/containerHeight in plugin state accordingly.
+    // Emits first event on initialization.
+    this.resizeObserver = new ResizeObserver((entries, observer) => {
+      for (const entry of entries) {
+        const { width, height } = entry.contentRect
+
+        this.uppy.log(`[Dashboard] resized: ${width} / ${height}`)
+
+        this.setPluginState({
+          containerWidth: width,
+          containerHeight: height,
+          areInsidesReadyToBeVisible: true
+        })
+      }
+    })
+    this.resizeObserver.observe(this.el.querySelector('.uppy-Dashboard-inner'))
+
+    // If ResizeObserver fails to emit an event telling us what size to use - default to the mobile view
+    this.makeDashboardInsidesVisibleAnywayTimeout = setTimeout(() => {
+      const pluginState = this.getPluginState()
+      if (!pluginState.areInsidesReadyToBeVisible) {
+        this.uppy.log("[Dashboard] resize event didn't fire on time: defaulted to mobile layout")
+
+        this.setPluginState({
+          areInsidesReadyToBeVisible: true
+        })
+      }
+    }, 1000)
+  }
+
+  stopListeningToResize () {
+    this.resizeObserver.disconnect()
+
+    clearTimeout(this.makeDashboardInsidesVisibleAnywayTimeout)
+  }
+
   initEvents () {
     // Modal open button
     const showModalTrigger = findAllDOMElements(this.opts.trigger)
@@ -488,21 +530,7 @@ module.exports = class Dashboard extends Plugin {
       this.handleDrop(files)
     })
 
-    // Watch for Dashboard container (`.uppy-Dashboard-inner`) resize
-    // and update containerWidth/containerHeight in plugin state accordingly
-    this.ro = new ResizeObserver((entries, observer) => {
-      for (const entry of entries) {
-        const { width, height } = entry.contentRect
-
-        this.uppy.log(`[Dashboard] resized: ${width} / ${height}`)
-
-        this.setPluginState({
-          containerWidth: width,
-          containerHeight: height
-        })
-      }
-    })
-    this.ro.observe(this.el.querySelector('.uppy-Dashboard-inner'))
+    this.startListeningToResize()
 
     this.uppy.on('plugin-remove', this.removeTarget)
     this.uppy.on('file-added', this.handleFileAdded)
@@ -526,7 +554,7 @@ module.exports = class Dashboard extends Plugin {
       showModalTrigger.forEach(trigger => trigger.removeEventListener('click', this.openModal))
     }
 
-    this.ro.unobserve(this.el.querySelector('.uppy-Dashboard-inner'))
+    this.stopListeningToResize()
 
     this.removeDragDropListener()
     // window.removeEventListener('resize', this.throttledUpdateDashboardElWidth)
@@ -719,6 +747,7 @@ module.exports = class Dashboard extends Plugin {
       currentWidth: pluginState.containerWidth,
       isWide: pluginState.containerWidth > 400,
       containerWidth: pluginState.containerWidth,
+      areInsidesReadyToBeVisible: pluginState.areInsidesReadyToBeVisible,
       isTargetDOMEl: this.isTargetDOMEl,
       parentElement: this.el,
       allowedFileTypes: this.uppy.opts.restrictions.allowedFileTypes,
@@ -744,7 +773,9 @@ module.exports = class Dashboard extends Plugin {
       showAddFilesPanel: false,
       activePickerPanel: false,
       metaFields: this.opts.metaFields,
-      targets: []
+      targets: [],
+      // We'll make them visible once .containerWidth is determined
+      areInsidesReadyToBeVisible: false
     })
 
     const { inline, closeAfterFinish } = this.opts

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません