@@ -9,7 +9,7 @@ some ready examples available at
99Something missing there that you you'd like to see? Let us know and we'll be
1010more than happy to add in examples.
1111
12- ### Viewing and downloading files
12+ ## Viewing and downloading files
1313
1414` get ` function can be used to get a file from a bucket. ` contentDisposition `
1515option can be to either ` attachment ` or ` inline ` depending on whether you want
@@ -82,7 +82,7 @@ export default function Avatar() {
8282
8383To trigger a download, set the ` contentDisposition ` option to ` attachment ` .
8484
85- ### Uploading files
85+ ## Uploading files
8686
8787` put ` function can be used to upload a file to a bucket.
8888
@@ -140,7 +140,7 @@ export default function Upload() {
140140</TabItem >
141141</Tabs >
142142
143- ### Client Uploads
143+ ## Client Uploads
144144
145145Tigris does not charge egress fees, but your hosting provider may charge them
146146for user uploads to Tigris. We care about your bandwidth costs, so we made it
@@ -152,6 +152,118 @@ We leverage the
152152[ presigned URLs] ( /docs/sdks/tigris/using-sdk#presigning-an-object ) features to
153153allow you to upload files directly to Tigris from the client side.
154154
155+ ### Multipart upload
156+
157+ <Tabs >
158+ <TabItem value = " server" label = " Server" default >
159+
160+ ``` ts
161+ // app/api/upload/route.ts
162+ import { NextRequest , NextResponse } from " next/server" ;
163+ import {
164+ initMultipartUpload ,
165+ getPartsPresignedUrls ,
166+ completeMultipartUpload ,
167+ UploadAction ,
168+ } from " @tigrisdata/storage" ;
169+
170+ export async function POST(request : NextRequest ) {
171+ try {
172+ const { path, operation, action, contentType, uploadId, parts, partIds } =
173+ await request .json ();
174+
175+ switch (action ) {
176+ case UploadAction .MultipartInit : {
177+ const result = await initMultipartUpload (path , {});
178+ return NextResponse .json ({ data: result .data });
179+ }
180+
181+ case UploadAction .MultipartParts : {
182+ if (! uploadId || ! parts ) {
183+ return NextResponse .json (
184+ { error: " uploadId and parts are required for multipart-parts" },
185+ { status: 400 },
186+ );
187+ }
188+ const result = await getPartsPresignedUrls (path , parts , uploadId , {});
189+ return NextResponse .json ({ data: result .data });
190+ }
191+
192+ case UploadAction .MultipartComplete : {
193+ if (! uploadId ) {
194+ return NextResponse .json (
195+ { error: " uploadId is required for multipart-complete" },
196+ { status: 400 },
197+ );
198+ }
199+ const result = await completeMultipartUpload (path , uploadId , partIds );
200+ return NextResponse .json ({ data: result .data });
201+ }
202+
203+ default :
204+ return NextResponse .json (
205+ { error: ` Unsupported operation: ${operation } ` },
206+ { status: 400 },
207+ );
208+ }
209+ } catch (error ) {
210+ return NextResponse .json (
211+ { error: " Failed to process upload request" },
212+ { status: 500 },
213+ );
214+ }
215+ }
216+ ```
217+
218+ </TabItem >
219+
220+ <TabItem value = " client" label = " Client" >
221+
222+ ``` tsx
223+ " use client" ;
224+
225+ import { upload } from " @tigrisdata/storage/client" ;
226+ import { useState } from " react" ;
227+
228+ export default function ClientUpload() {
229+ const [progress, setProgress] = useState <number >(0 );
230+ const [url, setUrl] = useState <string | null >(null );
231+ const handleFileChange = async (e : React .ChangeEvent <HTMLInputElement >) => {
232+ const file = e .target .files ?.[0 ];
233+ setProgress (0 );
234+ if (file ) {
235+ const result = await upload (` ${file .name } ` , file , {
236+ url: " /api/upload" ,
237+ access: " private" ,
238+ multipart: true ,
239+ partSize: 10 * 1024 * 1024 , // 10 MiB parts
240+ onUploadProgress : ({ loaded , total , percentage }) => {
241+ setProgress (percentage );
242+ if (percentage === 100 ) {
243+ setProgress (0 );
244+ }
245+ },
246+ });
247+ setUrl (result .url );
248+ }
249+ };
250+
251+ return (
252+ <>
253+ <input type = " file" onChange = { handleFileChange } />{ " " }
254+ { url && <div >Uploaded to: { url } </div >} { " " }
255+ { progress > 0 && progress < 100 && <div >{ progress } %</div >} { " " }
256+ </>
257+ );
258+ }
259+ ```
260+
261+ </TabItem >
262+
263+ </Tabs >
264+
265+ ### Simple upload
266+
155267<Tabs >
156268<TabItem value = " server" label = " Server" default >
157269
@@ -162,10 +274,9 @@ import { getPresignedUrl } from "@tigrisdata/storage";
162274
163275export async function POST(request : NextRequest ) {
164276 try {
165- const { path, method, contentType } = await request .json ();
277+ const { path, contentType } = await request .json ();
166278 const result = await getPresignedUrl (path , {
167- method ,
168- contentType ,
279+ operation: " put" ,
169280 expiresIn: 3600 , // 1 hour
170281 });
171282
0 commit comments