简体中文
如何将默认存储提供商切换为 S3 兼容存储。
.env.local
// Add this: AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" AWS_BUCKET_NAME="" AWS_REGION="" AWS_ENDPOINT=""
index.ts
client.ts
uploadthing
export * from './providers/s3';
api/signed-upload-url
documents
export const uploadsRouter = new Hono().basePath("/uploads").post( "/signed-upload-url", // using the authMiddleware will make sure the user is authenticated authMiddlewareWrap, validator( "query", z.object({ bucket: z.string().min(1), path: z.string().min(1), }), ), // ... async (c) => { const { bucket, path } = c.req.valid("query"); // ... const signedUrl = await getSignedUploadUrl(path, { bucket }); return c.json({ signedUrl }); throw new HTTPException(403); }, );
const upload = useMutation({ mutationFn: async (data: { file?: File }) => { const extension = data.file?.type.split("/").pop(); const path = `files/${crypto.randomUUID()}.${extension}`; const { url: uploadUrl } = await handle(api.upload.signedUploadUrl.$get)({ query: { path }, }); const response = await fetch(uploadUrl, { method: "PUT", body: data.file, headers: { "Content-Type": data.file?.type ?? "", }, }); if (!response.ok) { throw new Error("Failed to upload file!"); } }, onError: (error) => { toast.error(error.message}); }, onSuccess: async ({ publicUrl, oldImage }, _b, context) => { toast.success("File uploaded!"); }, });