@@ -12,7 +12,7 @@ import {
12
12
SDKInitOptions ,
13
13
} from "../types.js" ;
14
14
import {
15
- getOptimalSplitSize ,
15
+ getOptimalSplitSize , getSplitPdfAllowFailed ,
16
16
getSplitPdfConcurrencyLevel ,
17
17
getStartingPageNumber ,
18
18
loadPdf ,
@@ -40,10 +40,21 @@ export class SplitPdfHook
40
40
*/
41
41
client : HTTPClient | undefined ;
42
42
43
+
44
+ /**
45
+ * Keeps the strict-mode setting for splitPdfPage feature.
46
+ */
47
+ allowFailed : boolean | undefined ;
48
+
43
49
/**
44
50
* Maps lists responses to client operation.
45
51
*/
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 [ ] > = { } ;
47
58
48
59
/**
49
60
* Maps parallel requests to client operation.
@@ -115,6 +126,9 @@ export class SplitPdfHook
115
126
const concurrencyLevel = getSplitPdfConcurrencyLevel ( formData ) ;
116
127
console . info ( "Concurrency level set to %d" , concurrencyLevel )
117
128
129
+ this . allowFailed = getSplitPdfAllowFailed ( formData ) ;
130
+ console . info ( "Allow failed set to %s" , this . allowFailed )
131
+
118
132
const splitSize = await getOptimalSplitSize ( pagesCount , concurrencyLevel ) ;
119
133
console . info ( "Determined optimal split size of %d pages." , splitSize )
120
134
@@ -168,19 +182,30 @@ export class SplitPdfHook
168
182
setIndex += 1 ;
169
183
}
170
184
171
- this . partitionResponses [ operationID ] = new Array ( requests . length ) ;
185
+ this . partitionSuccessfulResponses [ operationID ] = new Array ( requests . length ) ;
186
+
187
+ const allowFailed = this . allowFailed ;
172
188
173
189
this . partitionRequests [ operationID ] = async . parallelLimit (
174
190
requests . slice ( 0 , - 1 ) . map ( ( req , pageIndex ) => async ( ) => {
175
191
const pageNumber = pageIndex + startingPageNumber ;
176
192
try {
177
193
const response = await this . client ! . request ( req ) ;
178
194
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 ] =
180
199
response . clone ( ) ;
200
+ if ( ! allowFailed ) {
201
+ throw new Error ( `Failed to send request for page ${ pageNumber } .` ) ;
202
+ }
181
203
}
182
204
} catch ( e ) {
183
205
console . error ( `Failed to send request for page ${ pageNumber } .` ) ;
206
+ if ( ! allowFailed ) {
207
+ throw e ;
208
+ }
184
209
}
185
210
} ) ,
186
211
concurrencyLevel
@@ -189,6 +214,54 @@ export class SplitPdfHook
189
214
return requests . at ( - 1 ) as Request ;
190
215
}
191
216
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
+
192
265
/**
193
266
* Executes after a successful API request. Awaits all parallel requests and combines
194
267
* the responses into a single response object.
@@ -203,22 +276,19 @@ export class SplitPdfHook
203
276
) : Promise < Response > {
204
277
const { operationID } = hookCtx ;
205
278
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 ) {
208
282
return response ;
209
283
}
210
284
211
- const headers = prepareResponseHeaders ( response ) ;
212
- const body = await prepareResponseBody ( [ ...responses , response ] ) ;
285
+ const finalResponse = await this . formFinalResponse ( response , successfulResponses , failedResponses ) ;
213
286
214
287
this . clearOperation ( operationID ) ;
215
288
216
- return new Response ( body , {
217
- headers : headers ,
218
- status : response . status ,
219
- statusText : response . statusText ,
220
- } ) ;
221
- }
289
+ return finalResponse ;
290
+ }
291
+
222
292
223
293
/**
224
294
* Executes after an unsuccessful API request. Awaits all parallel requests, if at least one
@@ -237,21 +307,19 @@ export class SplitPdfHook
237
307
) : Promise < { response : Response | null ; error : unknown } > {
238
308
const { operationID } = hookCtx ;
239
309
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 ) {
242
313
this . clearOperation ( operationID ) ;
243
314
return { response, error } ;
244
315
}
245
316
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
+ ) ;
255
323
256
324
this . clearOperation ( operationID ) ;
257
325
@@ -265,7 +333,8 @@ export class SplitPdfHook
265
333
* @param operationID - The ID of the operation to clear.
266
334
*/
267
335
clearOperation ( operationID : string ) {
268
- delete this . partitionResponses [ operationID ] ;
336
+ delete this . partitionSuccessfulResponses [ operationID ] ;
337
+ delete this . partitionFailedResponses [ operationID ] ;
269
338
delete this . partitionRequests [ operationID ] ;
270
339
}
271
340
@@ -276,15 +345,17 @@ export class SplitPdfHook
276
345
* @returns A promise that resolves to an array of responses, or undefined
277
346
* if there are no requests for the given operation ID.
278
347
*/
279
- async awaitAllRequests ( operationID : string ) : Promise < Response [ ] | undefined > {
348
+ async awaitAllRequests ( operationID : string ) : Promise < Map < string , Response [ ] > > {
280
349
const requests = this . partitionRequests [ operationID ] ;
350
+ const responseMap = new Map < string , Response [ ] > ( ) ;
281
351
282
352
if ( ! requests ) {
283
- return ;
353
+ return responseMap ;
284
354
}
285
-
286
355
await requests ;
287
356
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
289
360
}
290
361
}
0 commit comments