@@ -5,13 +5,47 @@ import { useRouter } from "next/navigation"
55import { S3Client } from "@aws-sdk/client-s3"
66import { useAuth } from "@/contexts/auth-context"
77import { configManager } from "@/lib/config"
8+ import { getServiceErrorMessage , getXmlErrorMessage } from "@/lib/error-handler"
89import type { SiteConfig } from "@/types/config"
910
1011interface S3Response {
1112 response ?: { body ?: string }
1213 [ key : string ] : unknown
1314}
1415
16+ type StreamCollector = ( streamBody : unknown ) => Promise < Uint8Array >
17+
18+ const readResponseBodyText = async (
19+ body : unknown ,
20+ streamCollector : StreamCollector | undefined ,
21+ ) : Promise < string | null > => {
22+ if ( typeof body === "string" ) {
23+ return body
24+ }
25+
26+ if ( body instanceof Uint8Array ) {
27+ return new TextDecoder ( "utf-8" ) . decode ( body )
28+ }
29+
30+ if ( ! body || ! streamCollector ) {
31+ return null
32+ }
33+
34+ const bytes = await streamCollector ( body )
35+ return new TextDecoder ( "utf-8" ) . decode ( bytes )
36+ }
37+
38+ const createS3ServiceError = ( message : string , statusCode : number ) => {
39+ const error = new Error ( message ) as Error & {
40+ Code ?: string
41+ $metadata ?: { httpStatusCode ?: number }
42+ }
43+ error . name = message
44+ error . Code = message
45+ error . $metadata = { httpStatusCode : statusCode }
46+ return error
47+ }
48+
1549function patchReplicationBody (
1650 body : string | undefined ,
1751 config : { Rules ?: Array < { DeleteReplication ?: { Status ?: string } } > } | undefined ,
@@ -95,6 +129,31 @@ export function S3Provider({ children }: { children: React.ReactNode }) {
95129 } ) as any ,
96130 { step : "serialize" , name : "injectDeleteReplication" , priority : "low" } ,
97131 )
132+ client . middlewareStack . addRelativeTo (
133+ ( ( next : any ) => async ( args : any ) => {
134+ const result = await next ( args )
135+ const response = result ?. response
136+ const statusCode = response ?. statusCode
137+
138+ if ( typeof statusCode === "number" && statusCode >= 300 ) {
139+ const streamCollector = client . config . streamCollector as StreamCollector | undefined
140+ const bodyText = await readResponseBodyText ( response . body , streamCollector )
141+ const errorMessage = bodyText ? ( getXmlErrorMessage ( bodyText ) ?? bodyText . trim ( ) ) : null
142+
143+ if ( errorMessage ) {
144+ throw createS3ServiceError ( errorMessage , statusCode )
145+ }
146+ }
147+
148+ return result
149+ } ) as any ,
150+ {
151+ name : "normalizeXmlErrorResponse" ,
152+ relation : "after" ,
153+ toMiddleware : "deserializerMiddleware" ,
154+ override : true ,
155+ } ,
156+ )
98157 client . middlewareStack . add (
99158 ( ( next : any ) => async ( args : any ) => {
100159 try {
@@ -137,8 +196,10 @@ export function S3Provider({ children }: { children: React.ReactNode }) {
137196 return { response : { statusCode : 401 , headers : { } } }
138197 }
139198 }
140- if ( err ?. Code ) {
141- throw new Error ( err . Code )
199+
200+ const serviceErrorMessage = getServiceErrorMessage ( error )
201+ if ( serviceErrorMessage ) {
202+ throw new Error ( serviceErrorMessage )
142203 }
143204 throw error
144205 }
0 commit comments