@@ -12,7 +12,7 @@ import {
1212 SDKInitOptions ,
1313} from "../types.js" ;
1414import {
15- getOptimalSplitSize ,
15+ getOptimalSplitSize , getSplitPdfAllowFailed ,
1616 getSplitPdfConcurrencyLevel ,
1717 getStartingPageNumber ,
1818 loadPdf ,
@@ -40,10 +40,21 @@ export class SplitPdfHook
4040 */
4141 client : HTTPClient | undefined ;
4242
43+
44+ /**
45+ * Keeps the strict-mode setting for splitPdfPage feature.
46+ */
47+ allowFailed : boolean | undefined ;
48+
4349 /**
4450 * Maps lists responses to client operation.
4551 */
46- partitionResponses : Record < string , Response [ ] > = { } ;
52+ partitionSuccessfulResponses : Record < string , Response [ ] > = { } ;
53+
54+ /**
55+ * Maps lists failed responses to client operation.
56+ */
57+ partitionFailedResponses : Record < string , Response [ ] > = { } ;
4758
4859 /**
4960 * Maps parallel requests to client operation.
@@ -115,6 +126,9 @@ export class SplitPdfHook
115126 const concurrencyLevel = getSplitPdfConcurrencyLevel ( formData ) ;
116127 console . info ( "Concurrency level set to %d" , concurrencyLevel )
117128
129+ this . allowFailed = getSplitPdfAllowFailed ( formData ) ;
130+ console . info ( "Allow failed set to %s" , this . allowFailed )
131+
118132 const splitSize = await getOptimalSplitSize ( pagesCount , concurrencyLevel ) ;
119133 console . info ( "Determined optimal split size of %d pages." , splitSize )
120134
@@ -168,19 +182,30 @@ export class SplitPdfHook
168182 setIndex += 1 ;
169183 }
170184
171- this . partitionResponses [ operationID ] = new Array ( requests . length ) ;
185+ this . partitionSuccessfulResponses [ operationID ] = new Array ( requests . length ) ;
186+
187+ const allowFailed = this . allowFailed ;
172188
173189 this . partitionRequests [ operationID ] = async . parallelLimit (
174190 requests . slice ( 0 , - 1 ) . map ( ( req , pageIndex ) => async ( ) => {
175191 const pageNumber = pageIndex + startingPageNumber ;
176192 try {
177193 const response = await this . client ! . request ( req ) ;
178194 if ( response . status === 200 ) {
179- ( this . partitionResponses [ operationID ] as Response [ ] ) [ pageIndex ] =
195+ ( this . partitionSuccessfulResponses [ operationID ] as Response [ ] ) [ pageIndex ] =
196+ response . clone ( ) ;
197+ } else {
198+ ( this . partitionFailedResponses [ operationID ] as Response [ ] ) [ pageIndex ] =
180199 response . clone ( ) ;
200+ if ( ! allowFailed ) {
201+ throw new Error ( `Failed to send request for page ${ pageNumber } .` ) ;
202+ }
181203 }
182204 } catch ( e ) {
183205 console . error ( `Failed to send request for page ${ pageNumber } .` ) ;
206+ if ( ! allowFailed ) {
207+ throw e ;
208+ }
184209 }
185210 } ) ,
186211 concurrencyLevel
@@ -189,6 +214,54 @@ export class SplitPdfHook
189214 return requests . at ( - 1 ) as Request ;
190215 }
191216
217+ /**
218+ * Forms the final response object based on the successful and failed responses.
219+ * @param response - The response object returned from the API request.
220+ * Expected to be a successful response.
221+ * @param successfulResponses - The list of successful responses.
222+ * @param failedResponses - The list of failed responses.
223+ * @returns The final response object.
224+ */
225+ async formFinalResponse ( response : Response ,
226+ successfulResponses : Response [ ] ,
227+ failedResponses : Response [ ]
228+ ) : Promise < Response > {
229+ let responseBody , responseStatus , responseStatusText ;
230+ const numFailedResponses = failedResponses ?. length ?? 0 ;
231+ const headers = prepareResponseHeaders ( response ) ;
232+
233+ if ( ! this . allowFailed && failedResponses && failedResponses . length > 0 ) {
234+ const failedResponse = failedResponses [ 0 ] ?. clone ( ) ;
235+ if ( failedResponse ) {
236+ responseBody = await failedResponse . text ( ) ;
237+ responseStatus = failedResponse . status ;
238+ responseStatusText = failedResponse . statusText ;
239+ } else {
240+ responseBody = JSON . stringify ( { "details:" : "Unknown error" } ) ;
241+ responseStatus = 503
242+ responseStatusText = "Unknown error"
243+ }
244+ console . warn (
245+ `${ numFailedResponses } requests failed. The partition operation is cancelled.`
246+ ) ;
247+ } else {
248+ responseBody = await prepareResponseBody ( [ ...successfulResponses , response ] ) ;
249+ responseStatus = response . status
250+ responseStatusText = response . statusText
251+ if ( numFailedResponses > 0 ) {
252+ console . warn (
253+ `${ numFailedResponses } requests failed. The results might miss some pages.`
254+ ) ;
255+ }
256+ }
257+ return new Response ( responseBody , {
258+ headers : headers ,
259+ status : responseStatus ,
260+ statusText : responseStatusText ,
261+ } ) ;
262+
263+ }
264+
192265 /**
193266 * Executes after a successful API request. Awaits all parallel requests and combines
194267 * the responses into a single response object.
@@ -203,22 +276,19 @@ export class SplitPdfHook
203276 ) : Promise < Response > {
204277 const { operationID } = hookCtx ;
205278 const responses = await this . awaitAllRequests ( operationID ) ;
206-
207- if ( ! responses ) {
279+ const successfulResponses = responses ?. get ( "success" ) ?? [ ] ;
280+ const failedResponses = responses ?. get ( "failed" ) ?? [ ] ;
281+ if ( ! successfulResponses ) {
208282 return response ;
209283 }
210284
211- const headers = prepareResponseHeaders ( response ) ;
212- const body = await prepareResponseBody ( [ ...responses , response ] ) ;
285+ const finalResponse = await this . formFinalResponse ( response , successfulResponses , failedResponses ) ;
213286
214287 this . clearOperation ( operationID ) ;
215288
216- return new Response ( body , {
217- headers : headers ,
218- status : response . status ,
219- statusText : response . statusText ,
220- } ) ;
221- }
289+ return finalResponse ;
290+ }
291+
222292
223293 /**
224294 * Executes after an unsuccessful API request. Awaits all parallel requests, if at least one
@@ -237,21 +307,19 @@ export class SplitPdfHook
237307 ) : Promise < { response : Response | null ; error : unknown } > {
238308 const { operationID } = hookCtx ;
239309 const responses = await this . awaitAllRequests ( operationID ) ;
240-
241- if ( ! responses ?. length ) {
310+ const successfulResponses = responses ?. get ( "success" ) ?? [ ] ;
311+ const failedResponses = responses ?. get ( "failed" ) ?? [ ] ;
312+ if ( ! successfulResponses ?. length ) {
242313 this . clearOperation ( operationID ) ;
243314 return { response, error } ;
244315 }
245316
246- const okResponse = responses [ 0 ] as Response ;
247- const headers = prepareResponseHeaders ( okResponse ) ;
248- const body = await prepareResponseBody ( responses ) ;
249-
250- const finalResponse = new Response ( body , {
251- headers : headers ,
252- status : okResponse . status ,
253- statusText : okResponse . statusText ,
254- } ) ;
317+ const okResponse = successfulResponses [ 0 ] as Response ;
318+ const finalResponse = await this . formFinalResponse (
319+ okResponse ,
320+ successfulResponses . slice ( 1 ) ,
321+ failedResponses
322+ ) ;
255323
256324 this . clearOperation ( operationID ) ;
257325
@@ -265,7 +333,8 @@ export class SplitPdfHook
265333 * @param operationID - The ID of the operation to clear.
266334 */
267335 clearOperation ( operationID : string ) {
268- delete this . partitionResponses [ operationID ] ;
336+ delete this . partitionSuccessfulResponses [ operationID ] ;
337+ delete this . partitionFailedResponses [ operationID ] ;
269338 delete this . partitionRequests [ operationID ] ;
270339 }
271340
@@ -276,15 +345,17 @@ export class SplitPdfHook
276345 * @returns A promise that resolves to an array of responses, or undefined
277346 * if there are no requests for the given operation ID.
278347 */
279- async awaitAllRequests ( operationID : string ) : Promise < Response [ ] | undefined > {
348+ async awaitAllRequests ( operationID : string ) : Promise < Map < string , Response [ ] > > {
280349 const requests = this . partitionRequests [ operationID ] ;
350+ const responseMap = new Map < string , Response [ ] > ( ) ;
281351
282352 if ( ! requests ) {
283- return ;
353+ return responseMap ;
284354 }
285-
286355 await requests ;
287356
288- return this . partitionResponses [ operationID ] ?. filter ( ( e ) => e ) ?? [ ] ;
357+ responseMap . set ( "success" , this . partitionSuccessfulResponses [ operationID ] ?. filter ( ( e ) => e ) ?? [ ] ) ;
358+ responseMap . set ( "failed" , this . partitionFailedResponses [ operationID ] ?. filter ( ( e ) => e ) ?? [ ] ) ;
359+ return responseMap
289360 }
290361}
0 commit comments