mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-18 00:55:35 +00:00
@uppy/aws-s3: use default Body generic & export AwsBody (#5353)
This commit is contained in:
parent
7b92d9d2cf
commit
1ef39db22c
6 changed files with 61 additions and 37 deletions
|
|
@ -169,6 +169,36 @@ const uppy = new Uppy()
|
|||
});
|
||||
```
|
||||
|
||||
### Use with TypeScript
|
||||
|
||||
Uppy always puts the response to an upload in `file.response.body`. If you want
|
||||
this to be type safe with `@uppy/aws-s3`, you can import the `AwsBody` type and
|
||||
pass it as the second genric to `Uppy`.
|
||||
|
||||
```ts {3,12} showLineNumbers
|
||||
import Uppy from '@uppy/core';
|
||||
import Dashboard from '@uppy/dashboard';
|
||||
import AwsS3, { type AwsBody } from '@uppy/aws-s3';
|
||||
|
||||
import '@uppy/core/dist/style.min.css';
|
||||
import '@uppy/dashboard/dist/style.min.css';
|
||||
|
||||
// Set this to `any` or `Record<string, unknown>`
|
||||
// if you do not set any metadata yourself
|
||||
type Meta = { license: string };
|
||||
|
||||
const uppy = new Uppy<Meta, AwsBody>()
|
||||
.use(Dashboard, { inline: true, target: 'body' })
|
||||
.use(AwsS3, { endpoint: '...' });
|
||||
|
||||
const id = uppy.addFile(/* ... */);
|
||||
|
||||
await uppy.upload();
|
||||
|
||||
const body = uppy.getFile(id).response.body!;
|
||||
const { location } = body; // This is now type safe
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Options
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type { Meta, Body, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type {
|
||||
RateLimitedQueue,
|
||||
WrapPromiseFunctionType,
|
||||
|
|
@ -6,7 +6,7 @@ import type {
|
|||
import { pausingUploadReason, type Chunk } from './MultipartUploader.ts'
|
||||
import type AwsS3Multipart from './index.js'
|
||||
import { throwIfAborted } from './utils.ts'
|
||||
import type { Body, UploadPartBytesResult, UploadResult } from './utils.js'
|
||||
import type { UploadPartBytesResult, UploadResult } from './utils.js'
|
||||
import type { AwsS3MultipartOptions, uploadPartBytes } from './index.js'
|
||||
|
||||
function removeMetadataFromURL(urlString: string) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import type { Uppy } from '@uppy/core'
|
||||
import { AbortController } from '@uppy/utils/lib/AbortController'
|
||||
import type { Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type { Meta, Body, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type { HTTPCommunicationQueue } from './HTTPCommunicationQueue.js'
|
||||
import type { Body } from './utils.js'
|
||||
|
||||
const MB = 1024 * 1024
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|||
import 'whatwg-fetch'
|
||||
import nock from 'nock'
|
||||
import Core from '@uppy/core'
|
||||
import AwsS3Multipart from './index.ts'
|
||||
import type { Body } from './utils.js'
|
||||
import AwsS3Multipart, { type AwsBody } from './index.ts'
|
||||
|
||||
const KB = 1024
|
||||
const MB = KB * KB
|
||||
|
|
@ -13,20 +12,18 @@ describe('AwsS3Multipart', () => {
|
|||
beforeEach(() => nock.disableNetConnect())
|
||||
|
||||
it('Registers AwsS3Multipart upload plugin', () => {
|
||||
const core = new Core<any, Body>()
|
||||
core.use(AwsS3Multipart)
|
||||
const core = new Core().use(AwsS3Multipart)
|
||||
|
||||
// @ts-expect-error private property
|
||||
const pluginNames = core[Symbol.for('uppy test: getPlugins')](
|
||||
'uploader',
|
||||
).map((plugin: AwsS3Multipart<any, Body>) => plugin.constructor.name)
|
||||
).map((plugin: AwsS3Multipart<any, AwsBody>) => plugin.constructor.name)
|
||||
expect(pluginNames).toContain('AwsS3Multipart')
|
||||
})
|
||||
|
||||
describe('companionUrl assertion', () => {
|
||||
it('Throws an error for main functions if configured without companionUrl', () => {
|
||||
const core = new Core<any, Body>()
|
||||
core.use(AwsS3Multipart)
|
||||
const core = new Core().use(AwsS3Multipart)
|
||||
const awsS3Multipart = core.getPlugin('AwsS3Multipart')!
|
||||
|
||||
const err = 'Expected a `endpoint` option'
|
||||
|
|
@ -47,8 +44,7 @@ describe('AwsS3Multipart', () => {
|
|||
|
||||
describe('non-multipart upload', () => {
|
||||
it('should handle POST uploads', async () => {
|
||||
const core = new Core<any, Body>()
|
||||
core.use(AwsS3Multipart, {
|
||||
const core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: false,
|
||||
limit: 0,
|
||||
getUploadParameters: () => ({
|
||||
|
|
@ -103,11 +99,11 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
describe('without companionUrl (custom main functions)', () => {
|
||||
let core: Core<any, Body>
|
||||
let awsS3Multipart: AwsS3Multipart<any, Body>
|
||||
let core: Core<any, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<any, AwsBody>
|
||||
|
||||
beforeEach(() => {
|
||||
core = new Core<any, Body>()
|
||||
core = new Core<any, AwsBody>()
|
||||
core.use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
limit: 0,
|
||||
|
|
@ -254,7 +250,7 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
it('retries uploadPartBytes when it fails once', async () => {
|
||||
const core = new Core<any, Body>().use(AwsS3Multipart, {
|
||||
const core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
createMultipartUpload,
|
||||
completeMultipartUpload: vi.fn(async () => ({ location: 'test' })),
|
||||
|
|
@ -287,7 +283,7 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
it('calls `upload-error` when uploadPartBytes fails after all retries', async () => {
|
||||
const core = new Core<any, Body>().use(AwsS3Multipart, {
|
||||
const core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
retryDelays: [10],
|
||||
createMultipartUpload,
|
||||
|
|
@ -328,7 +324,7 @@ describe('AwsS3Multipart', () => {
|
|||
const newToken = 'new token'
|
||||
|
||||
beforeEach(() => {
|
||||
core = new Core<any, Body>()
|
||||
core = new Core()
|
||||
core.use(AwsS3Multipart, {
|
||||
endpoint: '',
|
||||
headers: {
|
||||
|
|
@ -358,19 +354,17 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
describe('dynamic companionHeader using setOption', () => {
|
||||
let core: Core<any, Body>
|
||||
let awsS3Multipart: AwsS3Multipart<any, Body>
|
||||
let core: Core<any, AwsBody>
|
||||
let awsS3Multipart: AwsS3Multipart<any, AwsBody>
|
||||
const newToken = 'new token'
|
||||
|
||||
it('companionHeader is updated before uploading file', async () => {
|
||||
core = new Core<any, Body>()
|
||||
core = new Core()
|
||||
core.use(AwsS3Multipart)
|
||||
/* Set up preprocessor */
|
||||
core.addPreProcessor(() => {
|
||||
awsS3Multipart = core.getPlugin('AwsS3Multipart') as AwsS3Multipart<
|
||||
any,
|
||||
Body
|
||||
>
|
||||
awsS3Multipart =
|
||||
core.getPlugin<AwsS3Multipart<any, AwsBody>>('AwsS3Multipart')!
|
||||
awsS3Multipart.setOptions({
|
||||
endpoint: 'http://localhost',
|
||||
headers: {
|
||||
|
|
@ -391,7 +385,7 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
describe('file metadata across custom main functions', () => {
|
||||
let core: Core<any, Body>
|
||||
let core: Core
|
||||
const createMultipartUpload = vi.fn((file) => {
|
||||
core.setFileMeta(file.id, {
|
||||
...file.meta,
|
||||
|
|
@ -459,7 +453,7 @@ describe('AwsS3Multipart', () => {
|
|||
})
|
||||
|
||||
it('preserves file metadata if upload is completed', async () => {
|
||||
core = new Core<any, Body>().use(AwsS3Multipart, {
|
||||
core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
createMultipartUpload,
|
||||
signPart,
|
||||
|
|
@ -520,7 +514,7 @@ describe('AwsS3Multipart', () => {
|
|||
}
|
||||
})
|
||||
|
||||
core = new Core<any, Body>().use(AwsS3Multipart, {
|
||||
core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
createMultipartUpload,
|
||||
signPart: signPartWithAbort,
|
||||
|
|
@ -590,7 +584,7 @@ describe('AwsS3Multipart', () => {
|
|||
}
|
||||
})
|
||||
|
||||
core = new Core<any, Body>().use(AwsS3Multipart, {
|
||||
core = new Core().use(AwsS3Multipart, {
|
||||
shouldUseMultipart: true,
|
||||
createMultipartUpload,
|
||||
signPart: signPartWithPause,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import BasePlugin, {
|
|||
} from '@uppy/core/lib/BasePlugin.js'
|
||||
import { RequestClient } from '@uppy/companion-client'
|
||||
import type { RequestOptions } from '@uppy/utils/lib/CompanionClientProvider'
|
||||
import type { Body as _Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
|
||||
import type { Uppy } from '@uppy/core'
|
||||
import EventManager from '@uppy/core/lib/EventManager.js'
|
||||
import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'
|
||||
|
|
@ -21,7 +21,6 @@ import type {
|
|||
UploadResultWithSignal,
|
||||
MultipartUploadResultWithSignal,
|
||||
UploadPartBytesResult,
|
||||
Body,
|
||||
} from './utils.js'
|
||||
import createSignedURL from './createSignedURL.ts'
|
||||
import { HTTPCommunicationQueue } from './HTTPCommunicationQueue.ts'
|
||||
|
|
@ -33,13 +32,13 @@ interface MultipartFile<M extends Meta, B extends Body> extends UppyFile<M, B> {
|
|||
s3Multipart: UploadResult
|
||||
}
|
||||
|
||||
type PartUploadedCallback<M extends Meta, B extends _Body> = (
|
||||
type PartUploadedCallback<M extends Meta, B extends Body> = (
|
||||
file: UppyFile<M, B>,
|
||||
part: { PartNumber: number; ETag: string },
|
||||
) => void
|
||||
|
||||
declare module '@uppy/core' {
|
||||
export interface UppyEventMap<M extends Meta, B extends _Body> {
|
||||
export interface UppyEventMap<M extends Meta, B extends Body> {
|
||||
's3-multipart:part-uploaded': PartUploadedCallback<M, B>
|
||||
}
|
||||
}
|
||||
|
|
@ -289,6 +288,8 @@ const defaultOptions = {
|
|||
retryDelays: [0, 1000, 3000, 5000],
|
||||
} satisfies Partial<AwsS3MultipartOptions<any, any>>
|
||||
|
||||
export type { AwsBody } from './utils.ts'
|
||||
|
||||
export default class AwsS3Multipart<
|
||||
M extends Meta,
|
||||
B extends Body,
|
||||
|
|
@ -839,7 +840,7 @@ export default class AwsS3Multipart<
|
|||
...result,
|
||||
},
|
||||
status: 200,
|
||||
uploadURL: result.location,
|
||||
uploadURL: result.location as string,
|
||||
}
|
||||
|
||||
this.resetUploaderReferences(file.id)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { createAbortError } from '@uppy/utils/lib/AbortController'
|
||||
import type { Body as _Body } from '@uppy/utils/lib/UppyFile'
|
||||
import type { Body } from '@uppy/utils/lib/UppyFile'
|
||||
|
||||
import type { AwsS3Part } from './index.js'
|
||||
|
||||
|
|
@ -23,6 +23,6 @@ export type UploadPartBytesResult = {
|
|||
location?: string
|
||||
}
|
||||
|
||||
export interface Body extends _Body {
|
||||
export interface AwsBody extends Body {
|
||||
location: string
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue