This commit is contained in:
Merlijn Vos 2025-08-21 17:37:55 +02:00 committed by GitHub
commit a054062b4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
483 changed files with 3029 additions and 14582 deletions

View file

@ -0,0 +1,48 @@
---
"@uppy/dashboard": major
---
### Merge @uppy/status-bar into @uppy/dashboard
The `@uppy/status-bar` package has been merged into `@uppy/dashboard`. The plugin gave a false promise of flexibility as a standalone plugin but was always built tightly coupled for `@uppy/dashboard`. With the new headless components and hooks, we want go all in those components and remove the confusing, inflexible ones.
StatusBar is now rendered as an integrated component within Dashboard rather than as a separate plugin. The standalone `@uppy/status-bar` package is no longer maintained and should be removed from your dependencies.
#### Migration from standalone StatusBar to Dashboard
If you were using StatusBar as a separate plugin, you'll need to migrate to using Dashboard with the equivalent options.
**Before:**
```javascript
import StatusBar from '@uppy/status-bar'
uppy.use(StatusBar, {
target: '#status-bar',
showProgressDetails: true,
hideUploadButton: false,
hideAfterFinish: true
})
```
**Now:**
```javascript
import Dashboard from '@uppy/dashboard'
uppy.use(Dashboard, {
target: '#dashboard',
hideProgressDetails: false,
hideUploadButton: false,
hideAfterFinish: true
})
```
All StatusBar configuration options are now available directly as Dashboard options:
- `hideProgressDetails` - Hide detailed progress information (previously `showProgressDetails` with inverted logic)
- `hideUploadButton` - Hide the upload button
- `hideAfterFinish` - Hide status bar after upload completion
- `hideRetryButton` - Hide the retry button
- `hidePauseResumeButton` - Hide pause/resume controls
- `hideCancelButton` - Hide the cancel button
- `doneButtonHandler` - Custom handler for the done button

View file

@ -0,0 +1,70 @@
---
"@uppy/utils": major
"@uppy/angular": patch
"@uppy/google-photos-picker": patch
"example-companion-custom-provider": patch
"@uppy/google-drive-picker": patch
"@uppy/thumbnail-generator": patch
"@uppy/companion-client": patch
"@uppy/golden-retriever": patch
"@uppy/provider-views": patch
"@uppy/remote-sources": patch
"@uppy/screen-capture": patch
"@uppy/store-default": patch
"@uppy/google-drive": patch
"@uppy/image-editor": patch
"@uppy/react-native": patch
"@uppy/drop-target": patch
"@uppy/transloadit": patch
"@uppy/components": patch
"@uppy/compressor": patch
"@uppy/xhr-upload": patch
"@uppy/companion": patch
"@uppy/dashboard": patch
"@uppy/instagram": patch
"@uppy/facebook": patch
"@uppy/onedrive": patch
"@uppy/unsplash": patch
"angular": patch
"@uppy/dropbox": patch
"@uppy/locales": patch
"@uppy/aws-s3": patch
"@uppy/svelte": patch
"@uppy/webcam": patch
"@uppy/webdav": patch
"example-transloadit": patch
"@uppy/audio": patch
"@uppy/react": patch
"example-xhr-bundle": patch
"@uppy/core": patch
"@uppy/form": patch
"@uppy/zoom": patch
"example-sveltekit": patch
"@uppy/box": patch
"@uppy/tus": patch
"@uppy/url": patch
"@uppy/vue": patch
"example-angular": patch
"uppy": patch
"example-vue": patch
"@uppy-dev/dev": patch
---
Updated export maps for @uppy/utils: removed nested subpath exports; all utilities are now exported from the root index.js.
**Before :**
```typescript
import getFileTypeExtension from '@uppy/utils/lib/getFileTypeExtension'
```
**After :**
```typescript
import { getFileTypeExtension } from '@uppy/utils'
```

View file

@ -0,0 +1,70 @@
---
"@uppy/google-photos-picker": major
"@uppy/google-drive-picker": major
"@uppy/thumbnail-generator": major
"@uppy/companion-client": major
"@uppy/golden-retriever": major
"@uppy/provider-views": major
"@uppy/remote-sources": major
"@uppy/screen-capture": major
"@uppy/store-default": major
"@uppy/google-drive": major
"@uppy/image-editor": major
"@uppy/react-native": major
"@uppy/drop-target": major
"@uppy/transloadit": major
"@uppy/components": major
"@uppy/compressor": major
"@uppy/status-bar": major
"@uppy/xhr-upload": major
"@uppy/companion": major
"@uppy/dashboard": major
"@uppy/instagram": major
"@uppy/facebook": major
"@uppy/onedrive": major
"@uppy/unsplash": major
"@uppy/dropbox": major
"@uppy/locales": major
"@uppy/aws-s3": major
"@uppy/svelte": major
"@uppy/webcam": major
"@uppy/audio": major
"@uppy/react": major
"@uppy/utils": major
"@uppy/core": major
"@uppy/form": major
"@uppy/zoom": major
"@uppy/box": major
"@uppy/tus": major
"@uppy/url": major
"@uppy/vue": major
"uppy": major
---
### Export maps for all packages
All packages now have export maps. This is a breaking change in two cases:
1. The css imports have changed from `@uppy[package]/dist/styles.min.css` to `@uppy[package]/css/styles.min.css`
2. You were importing something that wasn't exported from the root, for instance `@uppy/core/lib/foo.js`. You can now only import things we explicitly exported.
#### Changed imports for `@uppy/react`, `@uppy/vue`, and `@uppy/svelte`
Some components, like Dashboard, require a peer dependency to work but since all components were exported from a single file you were forced to install all peer dependencies. Even if you never imported, for instance, the status bar component.
Every component that requires a peer dependency has now been moved to a subpath, such as `@uppy/react/dashboard`, so you only need to install the peer dependencies you need.
**Example for `@uppy/react`:**
**Before:**
```javascript
import { Dashboard, StatusBar } from "@uppy/react";
```
**Now:**
```javascript
import Dashboard from "@uppy/react/dashboard";
import StatusBar from "@uppy/react/status-bar";
```

View file

@ -0,0 +1,5 @@
---
"@uppy/companion": major
---
Make Companion ESM-only. As of Node.js 20.19.0, you can require(esm) if you haven't transitioned yet.

178
.github/MIGRATION.md vendored Normal file
View file

@ -0,0 +1,178 @@
# Migration
This is a temporary file that can be updated with any pending migration changes, before deleting them here and moving them to uppy.io. If we in the future decide to move uppy.io into this repo, then this file will not be needed anymore. See also https://github.com/transloadit/uppy/pull/5802
## Uppy 5.0
### Companion 5.x to 6.x
- Option `companionAllowedHosts` no longer wrapped in Regex start/end characters
(`^` and `$`). You now need to provide these yourself if you want an exact
match.
- Backwards compat token decryption removed: old Uppy auth tokens (created
before
[uppy%404.16.0](https://github.com/transloadit/uppy/releases/tag/uppy%404.16.0)
06d9a7c689e5123d41b38191074eb8bbd4ff5325) will become invalid and users who
have these old toknes will have to re-authenticate.
- Removed `token` param from `Provider` class methods: `list()`, `download()`,
`logout()`, `thumbnail()`. Please use: `providerUserSession`.`accessToken`
instead.
### @uppy/informer merged into @uppy/dashboard
The `@uppy/informer` plugin has been merged into `@uppy/dashboard` to reduce bundle size and improve maintainability. The `@uppy/informer` package is no longer maintained as a standalone package and should be removed from your dependencies.
### @uppy/progress-bar removed
The `@uppy/progress-bar` plugin has been removed as it provided minimal functionality that can be easily replicated with Uppy's built-in state management.
**Before:**
```js
import ProgressBar from '@uppy/progress-bar'
uppy.use(ProgressBar, { target: '#progress' })
```
**After:**
```js
// Custom progress bar using Uppy state
uppy.on('upload-progress', (file, progress) => {
const progressElement = document.getElementById('progress')
progressElement.style.width = `${progress.percentage}%`
progressElement.textContent = `${progress.percentage}%`
})
// Or listen to total progress
uppy.on('progress', (progress) => {
const progressElement = document.getElementById('progress')
progressElement.style.width = `${progress}%`
progressElement.textContent = `${progress}%`
})
```
**Migration steps:**
1. Remove `@uppy/progress-bar` from your dependencies
2. Create a custom progress indicator using Uppy's `progress` or `upload-progress` events.
3. Style your progress bar according to your design system.
### @uppy/drag-drop and @uppy/file-input removed
The `@uppy/drag-drop` and `@uppy/file-input` plugins have been removed in favor of more flexible, headless hooks. These hooks provide the same functionality but with maximum customization freedom.
**Before:**
```js
import DragDrop from '@uppy/drag-drop'
import FileInput from '@uppy/file-input'
uppy
.use(DragDrop, { target: '#drag-drop' })
.use(FileInput, { target: '#file-input' })
```
**After:**
```js
// React example
import { useDropzone, useFileInput } from '@uppy/react'
function MyUploader() {
const { getRootProps, getInputProps, isDragging } = useDropzone()
const { getButtonProps, getInputProps: getFileInputProps } = useFileInput()
return (
<div>
<input {...getInputProps()} className="hidden" />
<div {...getRootProps()} className={`dropzone ${isDragging ? 'dragging' : ''}`}>
<input {...getFileInputProps()} className="hidden" />
<button {...getButtonProps()}>Choose files</button>
<p>or drag and drop files here</p>
</div>
</div>
)
}
```
**Alternative: Use Dashboard**
```js
// If you want a complete UI solution, use Dashboard instead
import Dashboard from '@uppy/dashboard'
uppy.use(Dashboard, {
target: '#uppy-dashboard',
inline: true,
})
```
**Migration steps:**
1. Remove `@uppy/drag-drop` and `@uppy/file-input` from your dependencies
2. Choose one of these approaches:
- Use the framework-specific hooks (`@uppy/react`, `@uppy/vue`, `@uppy/svelte`) for maximum flexibility
- Use `@uppy/dashboard` for a complete, ready-to-use UI solution
3. Replace your existing components with custom implementations using the hooks or Dashboard
4. See [examples/](../examples/) for complete implementation examples
### Export maps for all packages
All packages now have export maps. This is a breaking change in two cases:
1. The css imports have changed from `@uppy[package]/dist/styles.min.css` to `@uppy[package]/css/styles.min.css`
2. You were importing something that wasn't exported from the root, for instance `@uppy/core/lib/foo.js`. You can now only import things we explicitly exported.
#### Changed imports for `@uppy/react`, `@uppy/vue`, and `@uppy/svelte`
Some components, like Dashboard, require a peer dependency to work but since all components were exported from a single file you were forced to install all peer dependencies. Even if you never imported, for instance, the status bar component.
Every component that requires a peer dependency has now been moved to a subpath, such as `@uppy/react/dashboard`, so you only need to install the peer dependencies you need.
**Example for `@uppy/react`:**
**Before:**
```javascript
import { Dashboard, StatusBar } from '@uppy/react'
```
**Now:**
```javascript
import Dashboard from '@uppy/react/dashboard'
import StatusBar from '@uppy/react/status-bar'
```
### @uppy/status-bar merged into @uppy/dashboard
The `@uppy/status-bar` package has been merged into `@uppy/dashboard`. The plugin gave a false promise of flexibility as a standalone plugin but was always built tightly coupled for `@uppy/dashboard`. With the new headless components and hooks, we want go all in those components and remove the confusing, inflexible ones.
**Migration steps:**
1. Remove `@uppy/status-bar` from your dependencies
2. Replace StatusBar usage with Dashboard
3. Move all StatusBar options directly to Dashboard options
All StatusBar configuration options are now available as Dashboard options:
- `hideProgressDetails` - Hide detailed progress information
- `hideUploadButton` - Hide the upload button
- `hideAfterFinish` - Hide status bar after upload completion
- `hideRetryButton` - Hide the retry button
- `hidePauseResumeButton` - Hide pause/resume controls
- `hideCancelButton` - Hide the cancel button
- `doneButtonHandler` - Custom handler for the done button
```js
// Before - separate StatusBar plugin
import StatusBar from '@uppy/status-bar'
uppy.use(StatusBar, {
target: '#status-bar',
hideProgressDetails: true,
hideUploadButton: false,
hideAfterFinish: true
})
// After - use Dashboard with StatusBar options
import Dashboard from '@uppy/dashboard'
uppy.use(Dashboard, {
target: '#dashboard',
hideProgressDetails: false,
hideUploadButton: false,
hideAfterFinish: true
})
```

View file

@ -20,10 +20,7 @@
"@uppy/angular": "workspace:*",
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/drag-drop": "workspace:*",
"@uppy/google-drive": "workspace:*",
"@uppy/progress-bar": "workspace:*",
"@uppy/status-bar": "workspace:*",
"@uppy/tus": "workspace:*",
"@uppy/utils": "workspace:*",
"@uppy/webcam": "workspace:*",

View file

@ -36,9 +36,6 @@ import Webcam from '@uppy/webcam'
</button>
</div>
<h2>Drag Drop Area</h2>
<uppy-drag-drop [uppy]="uppy" [props]="{}"></uppy-drag-drop>
<h2>Progress Bar</h2>
<uppy-progress-bar
[uppy]="uppy"

View file

@ -4,8 +4,6 @@ import { BrowserModule } from '@angular/platform-browser'
import {
UppyAngularDashboardModalModule,
UppyAngularDashboardModule,
UppyAngularDragDropModule,
UppyAngularProgressBarModule,
UppyAngularStatusBarModule,
} from '@uppy/angular'
import { AppComponent } from './app.component'
@ -17,8 +15,6 @@ import { AppComponent } from './app.component'
UppyAngularDashboardModule,
UppyAngularStatusBarModule,
UppyAngularDashboardModalModule,
UppyAngularDragDropModule,
UppyAngularProgressBarModule,
],
providers: [],
bootstrap: [AppComponent],

View file

@ -1,5 +1,3 @@
/* You can add global styles to this file, and also import other style files */
@import "@uppy/core/dist/style.css";
@import "@uppy/dashboard/dist/style.css";
@import "@uppy/drag-drop/dist/style.css";
@import "@uppy/progress-bar/dist/style.css";

View file

@ -31,14 +31,13 @@ function adaptData(res) {
/**
* an example of a custom provider module. It implements @uppy/companion's Provider interface
*/
class MyCustomProvider {
export default class MyCustomProvider {
static version = 2
static get oauthProvider() {
return 'myunsplash'
}
// eslint-disable-next-line class-methods-use-this
async list({ token, directory }) {
const path = directory ? `/${directory}/photos` : ''
@ -55,7 +54,6 @@ class MyCustomProvider {
return adaptData(await resp.json())
}
// eslint-disable-next-line class-methods-use-this
async download({ id, token }) {
const resp = await fetch(`${BASE_URL}/photos/${id}`, {
headers: {
@ -78,5 +76,3 @@ class MyCustomProvider {
return { stream: Readable.fromWeb(resp.body), size }
}
}
module.exports = MyCustomProvider

View file

@ -1,6 +0,0 @@
{
"rules": {
"react/react-in-jsx-scope": "off",
"no-use-before-define": "off"
}
}

View file

@ -1,4 +0,0 @@
{
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}

View file

@ -1,14 +0,0 @@
node_modules/
.expo/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
# macOS
.DS_Store

View file

@ -1,168 +0,0 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import Uppy from '@uppy/core'
import FilePicker from '@uppy/react-native'
import Tus from '@uppy/tus'
import { useCallback, useEffect, useState } from 'react'
import { Image, StyleSheet, Text, View } from 'react-native'
import FileList from './FileList'
import PauseResumeButton from './PauseResumeButton'
import ProgressBar from './ProgressBar'
import SelectFiles from './SelectFilesButton'
import getTusFileReader from './tusFileReader'
export default function App() {
const [state, _setState] = useState({
progress: 0,
total: 0,
file: null,
uploadURL: null,
isFilePickerVisible: false,
isPaused: false,
uploadStarted: false,
uploadComplete: false,
info: null,
totalProgress: 0,
})
const setState = useCallback(
(newState) => _setState((oldState) => ({ ...oldState, ...newState })),
[],
)
const [uppy] = useState(() =>
new Uppy({ autoProceed: true, debug: true }).use(Tus, {
endpoint: 'https://tusd.tusdemo.net/files/',
urlStorage: AsyncStorage,
fileReader: getTusFileReader,
chunkSize: 10 * 1024 * 1024, // keep the chunk size small to avoid memory exhaustion
}),
)
useEffect(() => {
uppy.on('upload-progress', (file, progress) => {
setState({
progress: progress.bytesUploaded,
total: progress.bytesTotal,
totalProgress: uppy.state.totalProgress,
uploadStarted: true,
})
})
uppy.on('upload-success', () => {
// console.log(file.name, response)
})
uppy.on('complete', (result) => {
setState({
status: result.successful[0]
? 'Upload complete ✅'
: 'Upload errored ❌',
uploadURL: result.successful[0] ? result.successful[0].uploadURL : null,
uploadComplete: true,
uploadStarted: false,
})
console.log('Upload complete:', result)
})
uppy.on('info-visible', () => {
const { info } = uppy.getState()
setState({
info,
})
console.log('uppy-info:', info)
})
uppy.on('info-hidden', () => {
setState({
info: null,
})
})
}, [setState, uppy])
const showFilePicker = () => {
setState({
isFilePickerVisible: true,
uploadStarted: false,
uploadComplete: false,
})
}
const hideFilePicker = () => {
setState({
isFilePickerVisible: false,
})
}
const togglePauseResume = () => {
if (state.isPaused) {
uppy.resumeAll()
setState({
isPaused: false,
})
} else {
uppy.pauseAll()
setState({
isPaused: true,
})
}
}
return (
<View style={styles.root}>
<Text style={styles.title}>Uppy in React Native</Text>
<View style={{ alignItems: 'center' }}>
<Image style={styles.logo} source={require('./assets/uppy-logo.png')} />
</View>
<SelectFiles showFilePicker={showFilePicker} />
{state.info
? <Text
style={{
marginBottom: 10,
marginTop: 10,
color: '#b8006b',
}}
>
{state.info.message}
</Text>
: null}
<ProgressBar progress={state.totalProgress} />
<PauseResumeButton
isPaused={state.isPaused}
onPress={togglePauseResume}
uploadStarted={state.uploadStarted}
uploadComplete={state.uploadComplete}
/>
{uppy && (
<FilePicker
uppy={uppy}
show={state.isFilePickerVisible}
onRequestClose={hideFilePicker}
companionUrl="http://localhost:3020"
/>
)}
{uppy && <FileList uppy={uppy} />}
{state.status && <Text>Status: {state.status}</Text>}
<Text>
{state.progress} of {state.total}
</Text>
</View>
)
}
const styles = StyleSheet.create({
root: {
paddingTop: 100,
paddingBottom: 20,
paddingLeft: 50,
paddingRight: 50,
flex: 1,
},
title: {
fontSize: 25,
marginBottom: 20,
textAlign: 'center',
},
logo: { width: 80, height: 78, marginBottom: 50 },
})

View file

@ -1,121 +0,0 @@
import getFileTypeIcon from '@uppy/dashboard/lib/utils/getFileTypeIcon.js'
import renderStringFromJSX from 'preact-render-to-string'
import { FlatList, Image, StyleSheet, Text, View } from 'react-native'
const fileIcon = require('./assets/file-icon.png')
const truncateString = (str) => {
const maxChars = 20
if (str.length > maxChars) {
return `${str.substring(0, 25)}...`
}
return str
}
function FileIcon() {
return (
<View style={styles.itemIconContainer}>
<Image style={styles.itemIcon} source={fileIcon} />
</View>
)
}
function UppyDashboardFileIcon({ type }) {
const icon = renderStringFromJSX(getFileTypeIcon(type).icon)
if (!icon) {
return <FileIcon />
}
const { color } = getFileTypeIcon(type)
return (
<View
style={{
...styles.itemIconContainer,
backgroundColor: color,
}}
>
<Text style={styles.itemType}>logo</Text>
</View>
)
}
export default function FileList({ uppy }) {
const uppyFiles = uppy.store.state.files
const uppyFilesArray = Object.keys(uppyFiles).map((id) => uppyFiles[id])
return (
<View style={styles.container}>
<FlatList
data={uppyFilesArray}
keyExtractor={(item) => item.id}
numColumns={2}
renderItem={({ item }) => {
return (
<View style={styles.item}>
{item.type === 'image'
? <Image
style={styles.itemImage}
source={{ uri: item.data.uri }}
/>
: <UppyDashboardFileIcon type={item.type} />}
<Text style={styles.itemName}>
{truncateString(item.name, 20)}
</Text>
<Text style={styles.itemType}>{item.type}</Text>
</View>
)
}}
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
marginTop: 20,
marginBottom: 20,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginRight: -25,
},
item: {
width: 100,
marginTop: 5,
marginBottom: 15,
marginRight: 25,
},
itemImage: {
width: 100,
height: 100,
borderRadius: 5,
marginBottom: 5,
},
itemIconContainer: {
width: 100,
height: 100,
borderRadius: 5,
marginBottom: 5,
backgroundColor: '#cfd3d6',
alignItems: 'center',
justifyContent: 'center',
},
itemIcon: {
width: 42,
height: 56,
},
itemIconSVG: {
width: 50,
height: 50,
},
itemName: {
fontSize: 13,
color: '#2c3e50',
fontWeight: '600',
},
itemType: {
fontWeight: '600',
fontSize: 12,
color: '#95a5a6',
},
})

View file

@ -1,30 +0,0 @@
import { StyleSheet, Text, TouchableHighlight } from 'react-native'
export default function PauseResumeButton({
uploadStarted,
uploadComplete,
isPaused,
onPress,
}) {
if (!uploadStarted || uploadComplete) {
return null
}
return (
<TouchableHighlight onPress={onPress} style={styles.button}>
<Text style={styles.text}>{isPaused ? 'Resume' : 'Pause'}</Text>
</TouchableHighlight>
)
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#cc0077',
padding: 10,
},
text: {
color: '#fff',
textAlign: 'center',
fontSize: 17,
},
})

View file

@ -1,38 +0,0 @@
import { StyleSheet, Text, View } from 'react-native'
const colorGreen = '#0b8600'
const colorBlue = '#006bb7'
export default function ProgressBar({ progress }) {
return (
<View style={styles.root}>
<View style={styles.wrapper}>
<View
style={[
styles.bar,
{
backgroundColor: progress === 100 ? colorGreen : colorBlue,
width: `${progress}%`,
},
]}
/>
</View>
<Text>{progress ? `${progress}%` : null}</Text>
</View>
)
}
const styles = StyleSheet.create({
root: {
marginTop: 15,
marginBottom: 15,
},
wrapper: {
height: 5,
overflow: 'hidden',
backgroundColor: '#dee1e3',
},
bar: {
height: 5,
},
})

View file

@ -1,21 +0,0 @@
import { StyleSheet, Text, TouchableHighlight } from 'react-native'
export default function SelectFiles({ showFilePicker }) {
return (
<TouchableHighlight onPress={showFilePicker} style={styles.button}>
<Text style={styles.text}>Select files</Text>
</TouchableHighlight>
)
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#cc0077',
padding: 15,
},
text: {
color: '#fff',
textAlign: 'center',
fontSize: 17,
},
})

View file

@ -1,30 +0,0 @@
{
"expo": {
"name": "react-native-expo",
"slug": "react-native-expo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -1,6 +0,0 @@
module.exports = (api) => {
api.cache(true)
return {
presets: ['babel-preset-expo'],
}
}

View file

@ -1,8 +0,0 @@
import { registerRootComponent } from 'expo'
import App from './App'
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App)

View file

@ -1,22 +0,0 @@
// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require('expo/metro-config')
const path = require('node:path')
// Find the project and workspace directories
const projectRoot = __dirname
// This can be replaced with `find-yarn-workspace-root`
const workspaceRoot = path.resolve(projectRoot, '../../')
const config = getDefaultConfig(projectRoot)
// 1. Watch all files within the monorepo
config.watchFolders = [workspaceRoot]
// 2. Let Metro know where to resolve packages and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
]
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
config.resolver.disableHierarchicalLookup = true
module.exports = config

View file

@ -1,36 +0,0 @@
{
"name": "example-react-native-expo",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@react-native-async-storage/async-storage": "1.23.1",
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/instagram": "workspace:*",
"@uppy/react-native": "workspace:*",
"@uppy/tus": "workspace:*",
"@uppy/url": "workspace:*",
"@uppy/xhr-upload": "workspace:*",
"base64-js": "^1.3.0",
"expo": "~52.0.0",
"expo-file-system": "~18.0.12",
"expo-status-bar": "~2.0.0",
"preact": "^10.5.13",
"preact-render-to-string": "^5.1.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.9",
"react-native-web": "~0.19.13"
},
"devDependencies": {
"@babel/core": "^7.12.9"
},
"private": true
}

View file

@ -1,29 +0,0 @@
# Uppy in React Native Expo (Beta)
⚠️ In Beta
`@uppy/react-native` is a basic Uppy component for React Native with Expo. It is
in Beta, and is not full-featured. You can select local images or videos, take a
picture with a camera or add any file from a remote url with Uppy Companion.
## Run it
To run this example, make sure you've correctly installed the **repository
root**:
```bash
yarn install
yarn run build
```
That will also install the dependencies for this example.
Then, start this example by doing:
```bash
cd examples/react-native-expo
yarn start
```
Then you'll see a menu within your terminal where you can chose where to open
the app (Android, iOS, device etc.)

View file

@ -1,30 +0,0 @@
import base64 from 'base64-js'
import * as FileSystem from 'expo-file-system'
export default function getTusFileReader(file, chunkSize, cb) {
FileSystem.getInfoAsync(file.uri, { size: true })
.then((info) => {
cb(null, new TusFileReader(file, info.size))
})
.catch(cb)
}
class TusFileReader {
constructor(file, size) {
this.file = file
this.size = size
}
slice(start, end, cb) {
const options = {
encoding: FileSystem.EncodingType.Base64,
length: Math.min(end, this.size) - start,
position: start,
}
FileSystem.readAsStringAsync(this.file.uri, options)
.then((data) => {
cb(null, base64.toByteArray(data))
})
.catch(cb)
}
}

View file

@ -18,7 +18,7 @@ import ScreenCapture from './ScreenCapture'
import Webcam from './Webcam'
import './app.css'
import '@uppy/react/dist/styles.css'
import '@uppy/react/css/style.css'
function App() {
const [uppy] = useState(() =>

View file

@ -1,28 +0,0 @@
# Redux
This example uses Uppy with a Redux store. The same Redux store is also used for
other parts of the application, namely the counter example. Each action is
logged to the console using
[redux-logger](https://github.com/theaqua/redux-logger).
This example supports the
[Redux Devtools extension](https://github.com/zalmoxisus/redux-devtools-extension),
including time travel.
## Run it
To run this example, make sure you've correctly installed the **repository
root**:
```sh
corepack yarn install
corepack yarn build
```
That will also install the dependencies for this example.
Then, again in the **repository root**, start this example by doing:
```sh
corepack yarn workspace @uppy-example/redux start
```

View file

@ -1,27 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Uppy example: Redux</title>
</head>
<body>
<main id="app">
<h1>A counter</h1>
<div>
<p>
Clicked: <span id="value">0</span> times
<button id="increment">+</button>
<button id="decrement">-</button>
<button id="incrementIfOdd">Increment if odd</button>
<button id="incrementAsync">Increment async</button>
</p>
</div>
<h1>An Uppy</h1>
<div id="uppy"></div>
</main>
<noscript>This app requires JavaScript.</noscript>
<script src="./main.js" type="module"></script>
</body>
</html>

View file

@ -1,93 +0,0 @@
import { configureStore } from '@reduxjs/toolkit'
import Uppy from '@uppy/core'
import Dashboard from '@uppy/dashboard'
import ReduxStore, * as uppyReduxStore from '@uppy/store-redux'
import Tus from '@uppy/tus'
import { applyMiddleware, combineReducers, compose } from 'redux'
import logger from 'redux-logger'
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
const reducer = combineReducers({
counter,
// You don't have to use the `uppy` key. But if you don't,
// you need to provide a custom `selector` to the `uppyReduxStore` call below.
uppy: uppyReduxStore.reducer,
})
let enhancer = applyMiddleware(uppyReduxStore.middleware(), logger)
if (typeof __REDUX_DEVTOOLS_EXTENSION__ !== 'undefined') {
enhancer = compose(enhancer, __REDUX_DEVTOOLS_EXTENSION__())
}
const store = configureStore({
reducer,
enhancers: [enhancer],
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [uppyReduxStore.STATE_UPDATE],
ignoreState: true,
},
}),
})
// Counter example from https://github.com/reactjs/redux/blob/master/examples/counter-vanilla/index.html
const valueEl = document.querySelector('#value')
function getCounter() {
return store.getState().counter
}
function render() {
valueEl.innerHTML = getCounter().toString()
}
render()
store.subscribe(render)
document.querySelector('#increment').onclick = () => {
store.dispatch({ type: 'INCREMENT' })
}
document.querySelector('#decrement').onclick = () => {
store.dispatch({ type: 'DECREMENT' })
}
document.querySelector('#incrementIfOdd').onclick = () => {
if (getCounter() % 2 !== 0) {
store.dispatch({ type: 'INCREMENT' })
}
}
document.querySelector('#incrementAsync').onclick = () => {
setTimeout(() => store.dispatch({ type: 'INCREMENT' }), 1000)
}
// Uppy using the same store
const uppy = new Uppy({
id: 'redux',
store: new ReduxStore({ store }),
// If we had placed our `reducer` elsewhere in Redux, eg. under an `uppy` key in the state for a profile page,
// we'd do something like:
//
// store: new ReduxStore({
// store: store,
// id: 'avatar',
// selector: state => state.pages.profile.uppy
// }),
debug: true,
})
uppy.use(Dashboard, {
target: '#app',
inline: true,
width: 400,
})
uppy.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })

View file

@ -1,21 +0,0 @@
{
"name": "example-redux",
"version": "0.0.0",
"type": "module",
"dependencies": {
"@reduxjs/toolkit": "^1.9.3",
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/store-redux": "workspace:*",
"@uppy/tus": "workspace:*",
"redux": "^4.2.1",
"redux-logger": "^3.0.6"
},
"devDependencies": {
"vite": "^7.0.6"
},
"private": true,
"scripts": {
"start": "vite"
}
}

View file

@ -15,8 +15,6 @@
"dependencies": {
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/drag-drop": "workspace:*",
"@uppy/progress-bar": "workspace:*",
"@uppy/screen-capture": "workspace:*",
"@uppy/svelte": "workspace:*",
"@uppy/tus": "workspace:*",

View file

@ -11,7 +11,7 @@ import {
} from '@uppy/svelte'
import Tus from '@uppy/tus'
import UppyWebcam from '@uppy/webcam'
import '@uppy/svelte/dist/styles.css'
import '@uppy/svelte/css/style.css'
import CustomDropzone from '../components/CustomDropzone.svelte'
import RemoteSource from '../components/RemoteSource.svelte'

View file

@ -2,7 +2,6 @@ import Uppy from '@uppy/core'
import Dashboard from '@uppy/dashboard'
import Form from '@uppy/form'
import ImageEditor from '@uppy/image-editor'
import ProgressBar from '@uppy/progress-bar'
import RemoteSources from '@uppy/remote-sources'
import Transloadit, { COMPANION_URL } from '@uppy/transloadit'
import Webcam from '@uppy/webcam'
@ -10,7 +9,6 @@ import Webcam from '@uppy/webcam'
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import '@uppy/image-editor/dist/style.css'
import '@uppy/progress-bar/dist/style.css'
const TRANSLOADIT_KEY = '35c1aed03f5011e982b6afe82599b6a0'
// A trivial template that resizes images, just for example purposes.
@ -182,15 +180,13 @@ const uppyWithoutUI = new Uppy({
restrictions: {
allowedFileTypes: ['.png'],
},
}).use(Transloadit, {
waitForEncoding: true,
params: {
auth: { key: TRANSLOADIT_KEY },
template_id: TEMPLATE_ID,
},
})
.use(Transloadit, {
waitForEncoding: true,
params: {
auth: { key: TRANSLOADIT_KEY },
template_id: TEMPLATE_ID,
},
})
.use(ProgressBar, { target: '#upload-progress' })
window.doUpload = (event) => {
const resultEl = document.querySelector('#upload-result')

View file

@ -12,7 +12,6 @@
"@uppy/drop-target": "workspace:*",
"@uppy/form": "workspace:*",
"@uppy/image-editor": "workspace:*",
"@uppy/progress-bar": "workspace:*",
"@uppy/remote-sources": "workspace:*",
"@uppy/transloadit": "workspace:*",
"@uppy/webcam": "workspace:*",

View file

@ -12,8 +12,6 @@
"dependencies": {
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/drag-drop": "workspace:*",
"@uppy/progress-bar": "workspace:*",
"@uppy/remote-sources": "workspace:*",
"@uppy/screen-capture": "workspace:*",
"@uppy/tus": "workspace:*",

View file

@ -84,4 +84,4 @@ const uppy = computed(() =>
)
</script>
<style src="@uppy/vue/dist/styles.css"></style>
<style src="@uppy/vue/css/style.css"></style>

View file

@ -9,7 +9,6 @@ const upload = multer({
function uploadRoute(req, res) {
res.json({
files: req.files.map((file) => {
// eslint-disable-next-line no-param-reassign
delete file.buffer
return file
}),

View file

@ -13,8 +13,8 @@
],
"scripts": {
"build": "turbo run --no-daemon build build:css --filter='./packages/@uppy/*' --filter='./packages/uppy'",
"build:clean": "git clean -Xfd packages e2e .parcel-cache coverage .turbo -e '!node_modules' -e '!**/node_modules/**/*'",
"build:watch": "turbo watch build build:css --filter='./packages/@uppy/*'",
"build:clean": "git clean -Xfd packages e2e .parcel-cache coverage .turbo .turbo -e '!node_modules' -e '!**/node_modules/**/*'",
"build:watch": "yarn build && turbo watch build build:css --filter='./packages/@uppy/*' --filter='./packages/uppy'",
"migrate:components": "yarn workspace @uppy/components migrate",
"check": "yarn exec biome check --write",
"check:ci": "yarn exec biome ci",

View file

@ -29,9 +29,6 @@
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
"@uppy/core": "workspace:^",
"@uppy/dashboard": "workspace:^",
"@uppy/drag-drop": "workspace:^",
"@uppy/progress-bar": "workspace:^",
"@uppy/status-bar": "workspace:^",
"@uppy/utils": "workspace:^"
},
"sideEffects": false

View file

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import type { Body, Meta } from "@uppy/utils";
import { DashboardModalComponent } from "./dashboard-modal.component";

View file

@ -11,7 +11,7 @@ import {
import { Uppy } from "@uppy/core";
import type { DashboardOptions } from "@uppy/dashboard";
import Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import type { Body, Meta } from "@uppy/utils";
import { UppyAngularWrapper } from "../../utils/wrapper";
@Component({

View file

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import type { Body, Meta } from "@uppy/utils";
import { DashboardComponent } from "./dashboard.component";
@Component({

View file

@ -11,7 +11,7 @@ import {
import { Uppy } from "@uppy/core";
import type { DashboardOptions } from "@uppy/dashboard";
import Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import type { Body, Meta } from "@uppy/utils";
import { UppyAngularWrapper } from "../../utils/wrapper";
@Component({

View file

@ -1,18 +0,0 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as DragDrop from "@uppy/drag-drop";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { DragDropComponent } from "./drag-drop.component";
@Component({
selector: "uppy-drag-drop-demo",
template: ` <uppy-drag-drop [uppy]="uppy" [props]="props"></uppy-drag-drop> `,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DragDropComponent],
})
export class DragDropDemoComponent<M extends Meta, B extends Body> {
uppy: Uppy<M, B> = new Uppy({ debug: true, autoProceed: true });
props: DragDrop.DragDropOptions = {};
}

View file

@ -1,24 +0,0 @@
import { async, type ComponentFixture, TestBed } from "@angular/core/testing";
import { DragDropComponent } from "./drag-drop.component";
describe("DragDropComponent", () => {
let component: DragDropComponent;
let fixture: ComponentFixture<DragDropComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DragDropComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DragDropComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,53 +0,0 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
inject,
type OnChanges,
type OnDestroy,
type SimpleChanges,
} from "@angular/core";
import { Uppy } from "@uppy/core";
import type { DragDropOptions } from "@uppy/drag-drop";
import DragDrop from "@uppy/drag-drop";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { UppyAngularWrapper } from "../../utils/wrapper";
@Component({
selector: "uppy-drag-drop",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class DragDropComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, DragDropOptions>
implements OnDestroy, OnChanges
{
el = inject(ElementRef);
@Input() uppy: Uppy<M, B> = new Uppy();
@Input() props: DragDropOptions = {};
/** Inserted by Angular inject() migration for backwards compatibility */
constructor(...args: unknown[]);
constructor() {
super();
}
ngOnInit() {
this.onMount(
{ id: "angular:DragDrop", target: this.el.nativeElement },
DragDrop,
);
}
ngOnChanges(changes: SimpleChanges): void {
this.handleChanges(changes, DragDrop);
}
ngOnDestroy(): void {
this.uninstall();
}
}

View file

@ -1,15 +0,0 @@
import { moduleMetadata } from "@storybook/angular";
import { DragDropDemoComponent } from "./drag-drop-demo.component";
export default {
title: "Drag Drop",
decorators: [
moduleMetadata({
declarations: [DragDropDemoComponent],
}),
],
};
export const Default = () => ({
component: DragDropDemoComponent,
});

View file

@ -1,105 +0,0 @@
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
inject,
type OnInit,
} from "@angular/core";
import { Uppy } from "@uppy/core";
import type { ProgressBarOptions } from "@uppy/progress-bar";
import Tus from "@uppy/tus";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { ProgressBarComponent } from "./progress-bar.component";
import { DragDropComponent } from "../drag-drop/drag-drop.component";
import { CommonModule } from "@angular/common";
@Component({
selector: "uppy-progress-bar-demo",
template: `
<section class="example-one">
<h5>autoProceed is on</h5>
<!-- Target DOM node #1 -->
<uppy-drag-drop [uppy]="uppyOne"></uppy-drag-drop>
<!-- Progress bar #1 -->
<uppy-progress-bar [uppy]="uppyOne" [props]="props"></uppy-progress-bar>
<!-- Uploaded files list #1 -->
<div class="uploaded-files" *ngIf="fileListOne?.length">
<h5>Uploaded files:</h5>
<ol>
<li *ngFor="let item of fileListOne">
<a [href]="item.url" target="_blank"> {{ item.fileName }}</a>
</li>
</ol>
</div>
</section>
<section class="example-two">
<h5>autoProceed is off</h5>
<!-- Target DOM node #1 -->
<uppy-drag-drop [uppy]="uppyTwo"></uppy-drag-drop>
<!-- Progress bar #1 -->
<uppy-progress-bar [uppy]="uppyTwo" [props]="props"></uppy-progress-bar>
<button (click)="upload()" class="upload-button">Upload</button>
<!-- Uploaded files list #2 -->
<div class="uploaded-files" *ngIf="fileListTwo?.length">
<h5>Uploaded files:</h5>
<ol>
<li *ngFor="let item of fileListTwo">
<a [href]="item.url" target="_blank"> {{ item.fileName }}</a>
</li>
</ol>
</div>
</section>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ProgressBarComponent, DragDropComponent, CommonModule],
})
export class ProgressBarDemoComponent<M extends Meta, B extends Body>
implements OnInit
{
private cdr = inject(ChangeDetectorRef);
uppyOne!: Uppy<M, B>;
uppyTwo!: Uppy<M, B>;
fileListOne: { url: string; fileName: string }[] = [];
fileListTwo: { url: string; fileName: string }[] = [];
props: ProgressBarOptions = {
hideAfterFinish: false,
};
upload(): void {
this.uppyTwo.upload();
}
/** Inserted by Angular inject() migration for backwards compatibility */
constructor(...args: unknown[]);
constructor() {}
updateFileList =
(target: string) =>
(file: any, response: any): void => {
(this as any)[target] = [
...(this as any)[target],
{ url: response.uploadURL, fileName: file.name },
];
this.cdr.markForCheck();
};
ngOnInit(): void {
this.uppyOne = new Uppy<M, B>({ debug: true, autoProceed: true })
.use(Tus, { endpoint: "https://master.tus.io/files/" })
.on("upload-success", this.updateFileList("fileListOne"));
this.uppyTwo = new Uppy<M, B>({ debug: true, autoProceed: false })
.use(Tus, { endpoint: "https://master.tus.io/files/" })
.on("upload-success", this.updateFileList("fileListTwo"));
}
}

View file

@ -1,24 +0,0 @@
import { async, type ComponentFixture, TestBed } from "@angular/core/testing";
import { ProgressBarComponent } from "./progress-bar.component";
describe("ProgressBarComponent", () => {
let component: ProgressBarComponent;
let fixture: ComponentFixture<ProgressBarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProgressBarComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProgressBarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,53 +0,0 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
inject,
type OnChanges,
type OnDestroy,
type SimpleChanges,
} from "@angular/core";
import { Uppy } from "@uppy/core";
import type { ProgressBarOptions } from "@uppy/progress-bar";
import ProgressBar from "@uppy/progress-bar";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { UppyAngularWrapper } from "../../utils/wrapper";
@Component({
selector: "uppy-progress-bar",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ProgressBarComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, ProgressBarOptions>
implements OnDestroy, OnChanges
{
el = inject(ElementRef);
@Input() uppy: Uppy<M, B> = new Uppy();
@Input() props: ProgressBarOptions = {};
/** Inserted by Angular inject() migration for backwards compatibility */
constructor(...args: unknown[]);
constructor() {
super();
}
ngOnInit() {
this.onMount(
{ id: "angular:ProgressBar", target: this.el.nativeElement },
ProgressBar,
);
}
ngOnChanges(changes: SimpleChanges): void {
this.handleChanges(changes, ProgressBar);
}
ngOnDestroy(): void {
this.uninstall();
}
}

View file

@ -1,17 +0,0 @@
import { CommonModule } from "@angular/common";
import { moduleMetadata } from "@storybook/angular";
import { ProgressBarDemoComponent } from "./progress-bar-demo.component";
export default {
title: "Progress Bar",
decorators: [
moduleMetadata({
imports: [CommonModule],
declarations: [ProgressBarDemoComponent],
}),
],
};
export const Default = () => ({
component: ProgressBarDemoComponent,
});

View file

@ -1,33 +0,0 @@
import { ChangeDetectionStrategy, Component, type OnInit } from "@angular/core";
import { Uppy } from "@uppy/core";
import FileInput from "@uppy/file-input";
import type * as StatusBar from "@uppy/status-bar";
import Tus from "@uppy/tus";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { StatusBarComponent } from "./status-bar.component";
@Component({
selector: "uppy-status-bar-demo",
template: `
<div class="UppyInput"></div>
<uppy-status-bar [uppy]="uppy" [props]="props"></uppy-status-bar>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [StatusBarComponent],
})
export class StatusBarDemoComponent<M extends Meta, B extends Body>
implements OnInit
{
uppy: Uppy<M, B> = new Uppy({ debug: true, autoProceed: true });
props: StatusBar.StatusBarOptions = {
hideUploadButton: true,
hideAfterFinish: false,
};
ngOnInit(): void {
this.uppy
.use(FileInput, { target: ".UppyInput", pretty: false })
.use(Tus, { endpoint: "https://master.tus.io/files/" });
}
}

View file

@ -1,24 +0,0 @@
import { async, type ComponentFixture, TestBed } from "@angular/core/testing";
import { StatusBarComponent } from "./status-bar.component";
describe("StatusBarComponent", () => {
let component: StatusBarComponent;
let fixture: ComponentFixture<StatusBarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StatusBarComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StatusBarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,53 +0,0 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
inject,
type OnChanges,
type OnDestroy,
type SimpleChanges,
} from "@angular/core";
import { Uppy } from "@uppy/core";
import type { StatusBarOptions } from "@uppy/status-bar";
import StatusBar from "@uppy/status-bar";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { UppyAngularWrapper } from "../../utils/wrapper";
@Component({
selector: "uppy-status-bar",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class StatusBarComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, StatusBarOptions>
implements OnDestroy, OnChanges
{
el = inject(ElementRef);
@Input() uppy: Uppy<M, B> = new Uppy();
@Input() props: StatusBarOptions = {};
/** Inserted by Angular inject() migration for backwards compatibility */
constructor(...args: unknown[]);
constructor() {
super();
}
ngOnInit() {
this.onMount(
{ id: "angular:StatusBar", target: this.el.nativeElement },
StatusBar,
);
}
ngOnChanges(changes: SimpleChanges): void {
this.handleChanges(changes, StatusBar);
}
ngOnDestroy(): void {
this.uninstall();
}
}

View file

@ -1,15 +0,0 @@
import { moduleMetadata } from "@storybook/angular";
import { StatusBarDemoComponent } from "./status-bar-demo.component";
export default {
title: "Status Bar",
decorators: [
moduleMetadata({
declarations: [StatusBarDemoComponent],
}),
],
};
export const Default = () => ({
component: StatusBarDemoComponent,
});

View file

@ -1,9 +1,7 @@
import type { ElementRef, SimpleChanges } from "@angular/core";
import type { UIPlugin, UIPluginOptions, Uppy } from "@uppy/core";
import type { DragDropOptions } from "@uppy/drag-drop";
import type { ProgressBarOptions } from "@uppy/progress-bar";
import type { StatusBarOptions } from "@uppy/status-bar";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import type { DashboardOptions } from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils";
export abstract class UppyAngularWrapper<
M extends Meta,
@ -11,7 +9,7 @@ export abstract class UppyAngularWrapper<
Opts extends UIPluginOptions,
PluginType extends UIPlugin<Opts, M, B> = UIPlugin<Opts, M, B>,
> {
abstract props: DragDropOptions | StatusBarOptions | ProgressBarOptions;
abstract props: DashboardOptions<M, B>;
abstract el: ElementRef;
abstract uppy: Uppy<M, B>;
private options: any;

View file

@ -4,6 +4,3 @@
export { DashboardComponent } from './lib/components/dashboard/dashboard.component'
export { DashboardModalComponent } from './lib/components/dashboard-modal/dashboard-modal.component'
export { DragDropComponent } from './lib/components/drag-drop/drag-drop.component'
export { ProgressBarComponent } from './lib/components/progress-bar/progress-bar.component'
export { StatusBarComponent } from './lib/components/status-bar/status-bar.component'

View file

@ -5,9 +5,6 @@
"dependsOn": [
"@uppy/core#build",
"@uppy/dashboard#build",
"@uppy/drag-drop#build",
"@uppy/progress-bar#build",
"@uppy/status-bar#build",
"@uppy/utils#build"
],
"inputs": [

View file

@ -16,6 +16,9 @@
"mediarecorder"
],
"type": "module",
"sideEffects": [
"*.css"
],
"homepage": "https://uppy.io",
"bugs": {
"url": "https://github.com/transloadit/uppy/issues"
@ -30,6 +33,12 @@
"dist",
"CHANGELOG.md"
],
"exports": {
".": "./lib/index.js",
"./css/style.css": "./dist/style.css",
"./css/style.min.css": "./dist/style.min.css",
"./package.json": "./package.json"
},
"dependencies": {
"@uppy/utils": "workspace:^",
"preact": "^10.5.13"

View file

@ -7,9 +7,8 @@ import type {
} from '@uppy/core'
import { UIPlugin } from '@uppy/core'
import getFileTypeExtension from '@uppy/utils/lib/getFileTypeExtension'
import type { LocaleStrings } from '@uppy/utils/lib/Translator'
import type { LocaleStrings } from '@uppy/utils'
import { getFileTypeExtension } from '@uppy/utils'
import packageJson from '../package.json' with { type: 'json' }
import locale from './locale.js'
import PermissionsScreen from './PermissionsScreen.js'

View file

@ -1,4 +1,4 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import type { I18n } from '@uppy/utils'
interface DiscardButtonProps {
onDiscard: () => void

View file

@ -1,4 +1,4 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import type { I18n } from '@uppy/utils'
import type { h } from 'preact'
interface PermissionsScreenProps {

View file

@ -1,4 +1,4 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import type { I18n } from '@uppy/utils'
interface RecordButtonProps {
recording: boolean

View file

@ -1,4 +1,4 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import type { I18n } from '@uppy/utils'
import { useEffect, useRef } from 'preact/hooks'
import AudioSourceSelect, {
type AudioSourceSelectProps,

View file

@ -1,4 +1,4 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import type { I18n } from '@uppy/utils'
interface SubmitButtonProps {
onSubmit: () => void

View file

@ -1,27 +0,0 @@
# @uppy/aws-s3-multipart
## 4.1.2
### Patch Changes
- 1b1a9e3: Define "files" in package.json
- Updated dependencies [1b1a9e3]
- @uppy/aws-s3@4.3.2
## 4.1.0
### Minor Changes
- 0c24c5a: Use TypeScript compiler instead of Babel
### Patch Changes
- Updated dependencies [0c24c5a]
- @uppy/aws-s3@4.3.0
## 4.0.0-beta.5
Released: 2024-05-03
Included in: Uppy v4.0.0-beta.5
- @uppy/aws-s3-multipart: Format (Murderlon)

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2018 Transloadit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,4 +0,0 @@
# @uppy/aws-s3-multipart
This package is deprecated. Use
[`@uppy/aws-s3`](https://npmjs.org/package/@uppy/aws-s3) instead.

View file

@ -1,38 +0,0 @@
{
"name": "@uppy/aws-s3-multipart",
"description": "Upload to Amazon S3 with Uppy and S3's Multipart upload strategy",
"version": "4.1.2",
"license": "MIT",
"main": "lib/index.js",
"type": "module",
"keywords": [
"file uploader",
"aws s3",
"amazon s3",
"s3",
"uppy",
"uppy-plugin",
"multipart"
],
"homepage": "https://uppy.io",
"bugs": {
"url": "https://github.com/transloadit/uppy/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/transloadit/uppy.git"
},
"files": [
"src",
"lib",
"dist",
"CHANGELOG.md"
],
"dependencies": {
"@uppy/aws-s3": "workspace:^"
},
"devDependencies": {
"@uppy/core": "workspace:^",
"typescript": "^5.8.3"
}
}

View file

@ -1,2 +0,0 @@
export * from '@uppy/aws-s3'
export { default } from '@uppy/aws-s3'

View file

@ -5,6 +5,7 @@
"license": "MIT",
"main": "lib/index.js",
"type": "module",
"sideEffects": false,
"scripts": {
"build": "tsc --build tsconfig.build.json",
"typecheck": "tsc --build",
@ -33,6 +34,10 @@
"dist",
"CHANGELOG.md"
],
"exports": {
".": "./lib/index.js",
"./package.json": "./package.json"
},
"dependencies": {
"@uppy/companion-client": "workspace:^",
"@uppy/utils": "workspace:^"

View file

@ -1,8 +1,5 @@
import type { Body, Meta, UppyFile } from '@uppy/core'
import type {
RateLimitedQueue,
WrapPromiseFunctionType,
} from '@uppy/utils/lib/RateLimitedQueue'
import type { RateLimitedQueue, WrapPromiseFunctionType } from '@uppy/utils'
import type AwsS3Multipart from './index.js'
import type {
AwsS3MultipartOptions,

View file

@ -1,6 +1,6 @@
import type { Uppy } from '@uppy/core'
import { AbortController } from '@uppy/utils/lib/AbortController'
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import type { Body, Meta, UppyFile } from '@uppy/utils'
import { AbortController } from '@uppy/utils'
import type { HTTPCommunicationQueue } from './HTTPCommunicationQueue.js'
const MB = 1024 * 1024

View file

@ -2,19 +2,18 @@ import { RequestClient } from '@uppy/companion-client'
import {
BasePlugin,
type DefinePluginOpts,
EventManager,
type PluginOpts,
type Uppy,
} from '@uppy/core'
import EventManager from '@uppy/core/lib/EventManager.js'
import { createAbortError } from '@uppy/utils/lib/AbortController'
import type { RequestOptions } from '@uppy/utils/lib/CompanionClientProvider'
import type { Body, Meta, RequestOptions, UppyFile } from '@uppy/utils'
import {
createAbortError,
filterFilesToEmitUploadStarted,
filterNonFailedFiles,
} from '@uppy/utils/lib/fileFilters'
import getAllowedMetaFields from '@uppy/utils/lib/getAllowedMetaFields'
import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
getAllowedMetaFields,
RateLimitedQueue,
} from '@uppy/utils'
import packageJson from '../package.json' with { type: 'json' }
import createSignedURL from './createSignedURL.js'
import { HTTPCommunicationQueue } from './HTTPCommunicationQueue.js'

View file

@ -1,5 +1,5 @@
import { createAbortError } from '@uppy/utils/lib/AbortController'
import type { Body } from '@uppy/utils/lib/UppyFile'
import type { Body } from '@uppy/utils'
import { createAbortError } from '@uppy/utils'
import type { AwsS3Part } from './index.js'

View file

@ -5,6 +5,7 @@
"license": "MIT",
"main": "lib/index.js",
"type": "module",
"sideEffects": false,
"scripts": {
"build": "tsc --build tsconfig.build.json",
"typecheck": "tsc --build"
@ -29,6 +30,10 @@
"dist",
"CHANGELOG.md"
],
"exports": {
".": "./lib/index.js",
"./package.json": "./package.json"
},
"dependencies": {
"@uppy/companion-client": "workspace:^",
"@uppy/provider-views": "workspace:^",

View file

@ -15,7 +15,7 @@ import type {
import { UIPlugin, type Uppy } from '@uppy/core'
import { ProviderViews } from '@uppy/provider-views'
import type { LocaleStrings } from '@uppy/utils/lib/Translator'
import type { LocaleStrings } from '@uppy/utils'
// biome-ignore lint/style/useImportType: h is not a type
import { type ComponentChild, h } from 'preact'
import packageJson from '../package.json' with { type: 'json' }

View file

@ -5,6 +5,7 @@
"license": "MIT",
"main": "lib/index.js",
"type": "module",
"sideEffects": false,
"scripts": {
"build": "tsc --build tsconfig.build.json",
"typecheck": "tsc --build",
@ -31,6 +32,10 @@
"dist",
"CHANGELOG.md"
],
"exports": {
".": "./lib/index.js",
"./package.json": "./package.json"
},
"dependencies": {
"@uppy/utils": "workspace:^",
"namespace-emitter": "^2.0.1",

View file

@ -5,10 +5,7 @@ import type {
UnknownProviderPlugin,
Uppy,
} from '@uppy/core'
import type {
CompanionClientProvider,
RequestOptions,
} from '@uppy/utils/lib/CompanionClientProvider'
import type { CompanionClientProvider, RequestOptions } from '@uppy/utils'
import { isOriginAllowed } from './getAllowedHosts.js'
import type { CompanionPluginOptions } from './index.js'
import RequestClient, { authErrorStatusCode } from './RequestClient.js'

View file

@ -1,10 +1,11 @@
import type Uppy from '@uppy/core'
import type { RequestOptions } from '@uppy/utils/lib/CompanionClientProvider'
import ErrorWithCause from '@uppy/utils/lib/ErrorWithCause'
import fetchWithNetworkError from '@uppy/utils/lib/fetchWithNetworkError'
import getSocketHost from '@uppy/utils/lib/getSocketHost'
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import UserFacingApiError from '@uppy/utils/lib/UserFacingApiError'
import type { Body, Meta, RequestOptions, UppyFile } from '@uppy/utils'
import {
ErrorWithCause,
fetchWithNetworkError,
getSocketHost,
UserFacingApiError,
} from '@uppy/utils'
import pRetry, { AbortError } from 'p-retry'
import packageJson from '../package.json' with { type: 'json' }
import AuthError from './AuthError.js'

View file

@ -1,5 +1,5 @@
import type { Body, Meta, Uppy } from '@uppy/core'
import type { CompanionClientSearchProvider } from '@uppy/utils/lib/CompanionClientProvider'
import type { CompanionClientSearchProvider } from '@uppy/utils'
import RequestClient, { type Opts } from './RequestClient.js'
const getName = (id: string): string => {

View file

@ -36,13 +36,14 @@ describe('isOriginAllowed', () => {
expect(isOriginAllowed('a', [/^.+$/])).toBeTruthy()
expect(isOriginAllowed('a', ['^.+$'])).toBeTruthy()
expect(
isOriginAllowed('www.transloadit.com', ['www\\.transloadit\\.com']),
isOriginAllowed('www.transloadit.com', ['^www\\.transloadit\\.com$']),
).toBeTruthy()
expect(
isOriginAllowed('www.transloadit.com', ['transloadit\\.com']),
isOriginAllowed('www.transloadit.com', ['^transloadit\\.com$']),
).toBeFalsy()
expect(isOriginAllowed('match', ['fail', 'match'])).toBeTruthy()
// todo maybe next major:
// expect(isOriginAllowed('www.transloadit.com', ['\\.transloadit\\.com$'])).toBeTruthy()
expect(
isOriginAllowed('www.transloadit.com', ['\\.transloadit\\.com$']),
).toBeTruthy()
})
})

View file

@ -5,8 +5,7 @@ function escapeRegex(string: string) {
function wrapInRegex(value?: string | RegExp): RegExp | undefined {
if (typeof value === 'string') {
// TODO in the next major we should change this to `new RegExp(value)` so that the user can control start/end characters
return new RegExp(`^${value}$`) // throws if invalid regex
return new RegExp(value) // throws if invalid regex
}
if (value instanceof RegExp) {
return value

View file

@ -0,0 +1,22 @@
class Gauge {
set = () => {}
}
export default function () {
const middleware = (req, res, next) => {
// simulate prometheus metrics endpoint:
if (req.url === '/metrics') {
res.setHeader('Content-Type', 'text/plain')
res.end('# Dummy metrics\n')
return
}
next()
}
middleware.promClient = {
collectDefaultMetrics: () => {},
Gauge,
}
return middleware
}

View file

@ -1,4 +1,4 @@
class Upload {
export class Upload {
constructor(file, options) {
this.url = 'https://tus.endpoint/files/foo-bar'
this.options = options
@ -18,4 +18,4 @@ class Upload {
}
}
module.exports = { Upload }
export default { Upload }

View file

@ -1,3 +1,3 @@
#!/usr/bin/env node
require('../lib/standalone/start-server')
import '../lib/standalone/start-server.js'

View file

@ -6,11 +6,18 @@
"types": "lib/companion.d.ts",
"author": "Transloadit.com",
"license": "MIT",
"sideEffects": false,
"homepage": "https://github.com/transloadit/uppy#readme",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/transloadit/uppy.git"
},
"exports": {
".": "./lib/companion.js",
"./standalone": "./lib/standalone/index.js",
"./package.json": "./package.json"
},
"keywords": [
"file uploader",
"progress",
@ -43,12 +50,12 @@
"escape-string-regexp": "4.0.0",
"express": "4.21.2",
"express-interceptor": "1.2.0",
"express-prom-bundle": "7.0.0",
"express-prom-bundle": "7",
"express-session": "1.18.1",
"fast-safe-stringify": "^2.1.1",
"formdata-node": "^6.0.3",
"got": "^13.0.0",
"grant": "5.4.22",
"grant": "^5.4.24",
"helmet": "^7.1.0",
"ioredis": "^5.3.2",
"ipaddr.js": "^2.0.1",
@ -67,7 +74,7 @@
"supports-color": "8.x",
"tus-js-client": "^4.1.0",
"validator": "^13.0.0",
"webdav": "5.7.1",
"webdav": "^5.8.0",
"ws": "8.17.1"
},
"devDependencies": {
@ -88,7 +95,6 @@
"@types/ws": "8.5.3",
"execa": "^9.6.0",
"http-proxy": "^1.18.1",
"jest": "^29.0.0",
"nock": "^13.1.3",
"supertest": "6.2.4",
"typescript": "^5.8.3",
@ -96,23 +102,20 @@
},
"files": [
"bin/",
"lib/"
"lib/",
"src/",
"CHANGELOG.md"
],
"jest": {
"testEnvironment": "node",
"testTimeout": 10000,
"automock": false
},
"scripts": {
"build": "tsc -p .",
"build": "tsc --build tsconfig.build.json",
"deploy": "kubectl apply -f infra/kube/companion-kube.yml",
"start": "node ./lib/standalone/start-server.js",
"start:dev": "bash start-dev",
"test": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand --silent",
"typecheck": "tsc --build"
"typecheck": "tsc --build",
"test": "vitest run --silent='passed-only'"
},
"engines": {
"node": "^18.20.0 || ^20.15.0 || >=22.0.0"
"node": "^20.19.3 || >=22.0.0"
},
"installConfig": {
"hoistingLimits": "workspaces"

View file

@ -1,40 +1,42 @@
const express = require('express')
const Grant = require('grant').default.express()
const merge = require('lodash/merge')
const cookieParser = require('cookie-parser')
const interceptor = require('express-interceptor')
const { randomUUID } = require('node:crypto')
const grantConfig = require('./config/grant')()
const providerManager = require('./server/provider')
const controllers = require('./server/controllers')
const s3 = require('./server/controllers/s3')
const url = require('./server/controllers/url')
const googlePicker = require('./server/controllers/googlePicker')
const createEmitter = require('./server/emitter')
const redis = require('./server/redis')
const jobs = require('./server/jobs')
const logger = require('./server/logger')
const middlewares = require('./server/middlewares')
const {
getMaskableSecrets,
import { randomUUID } from 'node:crypto'
import cookieParser from 'cookie-parser'
import express from 'express'
import interceptor from 'express-interceptor'
import grant from 'grant'
import merge from 'lodash/merge.js'
import packageJson from '../package.json' with { type: 'json' }
import {
defaultOptions,
getMaskableSecrets,
validateConfig,
} = require('./config/companion')
const {
} from './config/companion.js'
import grantConfigFn from './config/grant.js'
import googlePicker from './server/controllers/googlePicker.js'
import * as controllers from './server/controllers/index.js'
import s3 from './server/controllers/s3.js'
import url from './server/controllers/url.js'
import createEmitter from './server/emitter/index.js'
import { getURLBuilder } from './server/helpers/utils.js'
import * as jobs from './server/jobs.js'
import logger from './server/logger.js'
import * as middlewares from './server/middlewares.js'
import { getCredentialsOverrideMiddleware } from './server/provider/credentials.js'
import {
ProviderApiError,
ProviderUserError,
ProviderAuthError,
} = require('./server/provider/error')
const {
getCredentialsOverrideMiddleware,
} = require('./server/provider/credentials')
const { getURLBuilder } = require('./server/helpers/utils')
// @ts-ignore
const { version } = require('../package.json')
const { isOAuthProvider } = require('./server/provider/Provider')
ProviderUserError,
} from './server/provider/error.js'
import * as providerManager from './server/provider/index.js'
import { isOAuthProvider } from './server/provider/Provider.js'
import * as redis from './server/redis.js'
function setLoggerProcessName({ loggerProcessName }) {
import socket from './server/socket.js'
export { socket }
const grantConfig = grantConfigFn()
export function setLoggerProcessName({ loggerProcessName }) {
if (loggerProcessName != null) logger.setProcessName(loggerProcessName)
}
@ -72,14 +74,11 @@ const interceptGrantErrorResponse = interceptor((req, res) => {
})
// make the errors available publicly for custom providers
module.exports.errors = {
export const errors = {
ProviderApiError,
ProviderUserError,
ProviderAuthError,
}
module.exports.socket = require('./server/socket')
module.exports.setLoggerProcessName = setLoggerProcessName
/**
* Entry point into initializing the Companion app.
@ -87,7 +86,7 @@ module.exports.setLoggerProcessName = setLoggerProcessName
* @param {object} optionsArg
* @returns {{ app: import('express').Express, emitter: any }}}
*/
module.exports.app = (optionsArg = {}) => {
export function app(optionsArg = {}) {
setLoggerProcessName(optionsArg)
validateConfig(optionsArg)
@ -131,7 +130,7 @@ module.exports.app = (optionsArg = {}) => {
express.urlencoded({ extended: false }),
getCredentialsOverrideMiddleware(providers, options),
)
app.use(Grant(grantConfig))
app.use(grant.default.express(grantConfig))
app.use((req, res, next) => {
if (options.sendSelfEndpoint) {
@ -307,7 +306,7 @@ module.exports.app = (optionsArg = {}) => {
interval: options.periodicPingInterval,
count: options.periodicPingCount,
staticPayload: options.periodicPingStaticPayload,
version,
version: packageJson.version,
processId,
})

View file

@ -1,9 +1,9 @@
const fs = require('node:fs')
const { isURL } = require('validator')
const logger = require('../server/logger')
const { defaultGetKey } = require('../server/helpers/utils')
import fs from 'node:fs'
import validator from 'validator'
import { defaultGetKey } from '../server/helpers/utils.js'
import logger from '../server/logger.js'
const defaultOptions = {
export const defaultOptions = {
server: {
protocol: 'http',
path: '',
@ -28,7 +28,7 @@ const defaultOptions = {
/**
* @param {object} companionOptions
*/
function getMaskableSecrets(companionOptions) {
export function getMaskableSecrets(companionOptions) {
const secrets = []
const { providerOptions, customProviders, s3 } = companionOptions
@ -60,7 +60,7 @@ function getMaskableSecrets(companionOptions) {
*
* @param {object} companionOptions
*/
const validateConfig = (companionOptions) => {
export const validateConfig = (companionOptions) => {
const mandatoryOptions = ['secret', 'filePath', 'server.host']
/** @type {string[]} */
const unspecified = []
@ -148,7 +148,7 @@ const validateConfig = (companionOptions) => {
(!Array.isArray(periodicPingUrls) ||
periodicPingUrls.some(
(url2) =>
!isURL(url2, {
!validator.isURL(url2, {
protocols: ['http', 'https'],
require_protocol: true,
require_tld: false,
@ -162,9 +162,3 @@ const validateConfig = (companionOptions) => {
throw new TypeError('Option maxFilenameLength must be greater than 0')
}
}
module.exports = {
defaultOptions,
getMaskableSecrets,
validateConfig,
}

View file

@ -4,7 +4,7 @@ const defaults = {
}
// oauth configuration for provider services that are used.
module.exports = () => {
export default () => {
return {
// we need separate auth providers because scopes are different,
// and because it would be a too big rewrite to allow reuse of the same provider.

View file

@ -1,31 +1,27 @@
const tus = require('tus-js-client')
const { randomUUID } = require('node:crypto')
const validator = require('validator')
const { pipeline } = require('node:stream/promises')
const { join } = require('node:path')
const fs = require('node:fs')
const throttle = require('lodash/throttle')
const { once } = require('node:events')
const { FormData } = require('formdata-node')
const { Upload } = require('@aws-sdk/lib-storage')
const {
rfc2047EncodeMetadata,
import { randomUUID } from 'node:crypto'
import { once } from 'node:events'
import { createReadStream, createWriteStream, ReadStream } from 'node:fs'
import { stat, unlink } from 'node:fs/promises'
import { join } from 'node:path'
import { pipeline } from 'node:stream/promises'
import { Upload } from '@aws-sdk/lib-storage'
import { FormData } from 'formdata-node'
import got from 'got'
import throttle from 'lodash/throttle.js'
import { serializeError } from 'serialize-error'
import tus from 'tus-js-client'
import validator from 'validator'
import emitter from './emitter/index.js'
import headerSanitize from './header-blacklist.js'
import {
getBucket,
hasMatch,
jsonStringify,
rfc2047EncodeMetadata,
truncateFilename,
} = require('./helpers/utils')
const got = require('./got')
const { createReadStream, createWriteStream, ReadStream } = fs
const { stat, unlink } = fs.promises
const emitter = require('./emitter')
const { jsonStringify, hasMatch } = require('./helpers/utils')
const logger = require('./logger')
const headerSanitize = require('./header-blacklist')
const redis = require('./redis')
} from './helpers/utils.js'
import * as logger from './logger.js'
import * as redis from './redis.js'
// Need to limit length or we can get
// "MetadataTooLarge: Your metadata headers exceed the maximum allowed metadata size" in tus / S3
@ -40,7 +36,7 @@ function exceedsMaxFileSize(maxFileSize, size) {
return maxFileSize && size && size > maxFileSize
}
class ValidationError extends Error {
export class ValidationError extends Error {
name = 'ValidationError'
}
@ -82,7 +78,6 @@ function validateOptions(options) {
}
// validate protocol
// @todo this validation should not be conditional once the protocol field is mandatory
if (
options.protocol &&
!Object.keys(PROTOCOLS).some((key) => PROTOCOLS[key] === options.protocol)
@ -127,7 +122,7 @@ const states = {
done: 'done',
}
class Uploader {
export default class Uploader {
/** @type {import('ioredis').Redis} */
storage
@ -227,8 +222,6 @@ class Uploader {
}
_getUploadProtocol() {
// todo a default protocol should not be set. We should ensure that the user specifies their protocol.
// after we drop old versions of uppy client we can remove this
return this.options.protocol || PROTOCOLS.multipart
}
@ -530,8 +523,6 @@ class Uploader {
async #emitError(err) {
// delete stack to avoid sending server info to client
// see PR discussion https://github.com/transloadit/uppy/pull/3832
// @ts-ignore
const { serializeError } = await import('serialize-error')
const { stack, ...serializedErr } = serializeError(err)
const dataToEmit = {
action: 'error',
@ -691,7 +682,7 @@ class Uploader {
try {
const httpMethod =
(this.options.httpMethod || '').toUpperCase() === 'PUT' ? 'put' : 'post'
const runRequest = (await got)[httpMethod]
const runRequest = await got[httpMethod]
const response = await runRequest(url, reqOptions)
@ -782,6 +773,3 @@ class Uploader {
Uploader.FILE_NAME_PREFIX = 'uppy-file'
Uploader.STORAGE_PREFIX = 'companion'
module.exports = Uploader
module.exports.ValidationError = ValidationError

View file

@ -1,11 +1,10 @@
/**
* oAuth callback. Encrypts the access token and sends the new token with the response,
*/
const serialize = require('serialize-javascript')
const tokenService = require('../helpers/jwt')
const logger = require('../logger')
const oAuthState = require('../helpers/oauth-state')
import serialize from 'serialize-javascript'
import * as tokenService from '../helpers/jwt.js'
import * as oAuthState from '../helpers/oauth-state.js'
import logger from '../logger.js'
const closePageHtml = (origin) => `
<!DOCTYPE html>
@ -28,7 +27,7 @@ const closePageHtml = (origin) => `
* @param {object} res
* @param {Function} next
*/
module.exports = function callback(req, res, next) {
export default function callback(req, res, next) {
const { providerName } = req.params
const grant = req.session.grant || {}

View file

@ -1,4 +1,4 @@
const oAuthState = require('../helpers/oauth-state')
import * as oAuthState from '../helpers/oauth-state.js'
/**
* Derived from `cors` npm package.
@ -82,7 +82,7 @@ function getClientOrigin(base64EncodedState) {
* @param {object} req
* @param {object} res
*/
module.exports = function connect(req, res, next) {
export default function connect(req, res, next) {
const stateObj = oAuthState.generateState()
if (req.companion.options.server.oauthDomain) {
@ -116,4 +116,5 @@ module.exports = function connect(req, res, next) {
}
encodeStateAndRedirect(req, res, stateObj)
}
module.exports.isOriginAllowed = isOriginAllowed
export { isOriginAllowed }

View file

@ -1,6 +1,10 @@
const { respondWithError } = require('../provider/error')
import { respondWithError } from '../provider/error.js'
async function deauthCallback({ body, companion, headers }, res, next) {
export default async function deauthCallback(
{ body, companion, headers },
res,
next,
) {
// we need the provider instance to decide status codes because
// this endpoint does not cater to a uniform client.
// It doesn't respond to Uppy client like other endpoints.
@ -17,5 +21,3 @@ async function deauthCallback({ body, companion, headers }, res, next) {
next(err)
}
}
module.exports = deauthCallback

Some files were not shown because too many files have changed in this diff Show more