From 87af2e3b7f76defba24c49ecb3bf6d430bbb4f76 Mon Sep 17 00:00:00 2001 From: Teages Date: Fri, 12 Apr 2024 21:03:58 +0800 Subject: [PATCH 01/15] fix: wrong type for head of proxyHubBlob --- src/runtime/server/utils/blob.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/server/utils/blob.ts b/src/runtime/server/utils/blob.ts index 46f0e3d4..b01f8112 100644 --- a/src/runtime/server/utils/blob.ts +++ b/src/runtime/server/utils/blob.ts @@ -274,7 +274,7 @@ export function proxyHubBlob(projectUrl: string, secretKey?: string) { }) }, async head(pathname: string) { - return await blobAPI(`/head/${decodeURI(pathname)}`, { + return await blobAPI(`/head/${decodeURI(pathname)}`, { method: 'GET' }) }, From 0bf82145a3b26f2047d70cf3b382e923fa84f168 Mon Sep 17 00:00:00 2001 From: Teages Date: Fri, 12 Apr 2024 21:07:23 +0800 Subject: [PATCH 02/15] feat: multipart upload --- playground/pages/blob.vue | 77 ++++++++- .../api/blob/mpu/[...pathname].delete.ts | 22 +++ .../server/api/blob/mpu/[...pathname].put.ts | 43 +++++ playground/server/api/blob/mpu/index.post.ts | 55 +++++++ .../api/_hub/blob/mpu/[...pathname].delete.ts | 31 ++++ .../api/_hub/blob/mpu/[...pathname].put.ts | 52 ++++++ .../server/api/_hub/blob/mpu/index.post.ts | 59 +++++++ src/runtime/server/utils/blob.ts | 148 +++++++++++++++++- 8 files changed, 480 insertions(+), 7 deletions(-) create mode 100644 playground/server/api/blob/mpu/[...pathname].delete.ts create mode 100644 playground/server/api/blob/mpu/[...pathname].put.ts create mode 100644 playground/server/api/blob/mpu/index.post.ts create mode 100644 src/runtime/server/api/_hub/blob/mpu/[...pathname].delete.ts create mode 100644 src/runtime/server/api/_hub/blob/mpu/[...pathname].put.ts create mode 100644 src/runtime/server/api/_hub/blob/mpu/index.post.ts diff --git a/playground/pages/blob.vue b/playground/pages/blob.vue index 27038277..f082113e 100644 --- a/playground/pages/blob.vue +++ b/playground/pages/blob.vue @@ -1,4 +1,6 @@ + + +``` + #### Params ::field-group @@ -194,6 +220,36 @@ You can also use the `delete()` method as alias of `del()`. Returns nothing. +### `handleMultipartUpload()` + +Handle the request to support multipart upload. + +```ts [server/api/files/multipart/[action\\]/[...pathname\\].ts] +export default eventHandler(async (event) => { + return await hubBlob().handleMultipartUpload(event) +}) +``` + +::important +Make sure your route includes `[action]` and `[...pathname]` params. +:: + +On the client side, you can use the `useMultipartUpload()` composable to upload a file in parts. + +```vue + +``` + +::note{to="#usemultipartupload"} +See [`useMultipartUpload()`](#usemultipartupload) on usage details. +:: + ### `createMultipartUpload()` ::note @@ -346,23 +402,6 @@ async function uploadLargeFile(file: File) { Returns a `BlobMultipartUpload` -### `handleMultipartUpload()` - -Handle the multipart upload request. - -::note -Make sure your route includes `[action]` and `[...pathname]` params. -:: - -```ts [server/api/files/multipart/[action\\]/[...pathname\\].ts] -export default eventHandler(async (event) => { - await hubBlob().handleMultipartUpload(event) -}) -``` - -::note -Use [`useMultipartUpload()`](#usemultipartupload) to upload in client. -:: #### Params @@ -410,7 +449,11 @@ Throws an error if `file` doesn't meet the requirements. ## `useMultipartUpload()` -Client composable that creates a multipart upload helper. +::note +This is a composable to be used in the Vue side of your application (not the `server/` directory). +:: + +Application composable that creates a multipart upload helper. ```ts [utils/multipart-upload.ts] export const upload = useMultipartUpload('/api/files/multipart') @@ -511,7 +554,6 @@ interface BlobListResult { } ``` - ## Examples ### List blobs with pagination diff --git a/playground/server/api/blob/multipart/[action]/[...pathname].ts b/playground/server/api/blob/multipart/[action]/[...pathname].ts index 9c1b0ae7..94be14e6 100644 --- a/playground/server/api/blob/multipart/[action]/[...pathname].ts +++ b/playground/server/api/blob/multipart/[action]/[...pathname].ts @@ -1,3 +1,5 @@ export default eventHandler(async (event) => { - await hubBlob().handleMultipartUpload(event) + return await hubBlob().handleMultipartUpload(event, { + addRandomSuffix: true + }) }) diff --git a/src/runtime/server/utils/blob.ts b/src/runtime/server/utils/blob.ts index 57c91807..23cfb2c5 100644 --- a/src/runtime/server/utils/blob.ts +++ b/src/runtime/server/utils/blob.ts @@ -231,7 +231,7 @@ interface HubBlob { * Handle the multipart upload request. * Make sure your route includes `[action]` and `[...pathname]` params. */ - handleMultipartUpload(event: H3Event): Promise + handleMultipartUpload(event: H3Event, options?: BlobMultipartOptions): Promise } /** @@ -488,13 +488,11 @@ function createMultipartUploadHandler( ): HubBlob['handleMultipartUpload'] { const { createMultipartUpload, resumeMultipartUpload } = hub - const createHandler = async (event: H3Event) => { + const createHandler = async (event: H3Event, options?: BlobMultipartOptions) => { const { pathname } = await getValidatedRouterParams(event, z.object({ pathname: z.string().min(1) }).parse) - const options = await readValidatedBody(event, z.record(z.string(), z.any()).optional().parse) - try { const object = await createMultipartUpload(pathname, options) return { @@ -576,7 +574,7 @@ function createMultipartUploadHandler( } } - const handler = async (event: H3Event) => { + const handler = async (event: H3Event, options?: BlobMultipartOptions) => { const method = event.method const { action } = await getValidatedRouterParams(event, z.object({ action: z.enum(['create', 'upload', 'complete', 'abort']) @@ -585,7 +583,7 @@ function createMultipartUploadHandler( if (action === 'create' && method === 'POST') { return { action, - data: await createHandler(event) + data: await createHandler(event, options) } } @@ -613,8 +611,8 @@ function createMultipartUploadHandler( throw createError({ status: 405 }) } - return async (event: H3Event) => { - const result = await handler(event) + return async (event: H3Event, options?: BlobMultipartOptions) => { + const result = await handler(event, options) if (result.data) { event.respondWith(Response.json(result.data)) From 09d96e6fe305d6e8498090afd50480f47c6660b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Fri, 31 May 2024 18:25:32 +0200 Subject: [PATCH 15/15] up --- src/runtime/compsables/useUpload.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runtime/compsables/useUpload.ts b/src/runtime/compsables/useUpload.ts index 456d15d2..ea541eef 100644 --- a/src/runtime/compsables/useUpload.ts +++ b/src/runtime/compsables/useUpload.ts @@ -12,7 +12,6 @@ interface UploadOptions extends FetchOptions { * @default true */ multiple?: boolean - } export function useUpload(apiBase: string, options: UploadOptions & { multiple: false }): (data: FileList | HTMLInputElement | File[] | File) => Promise