Skip to content

Commit 189a3f7

Browse files
committed
Error handling tests and hardening
1 parent 2af9c96 commit 189a3f7

File tree

4 files changed

+344
-58
lines changed

4 files changed

+344
-58
lines changed

src/utils/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export { default as getOrigins } from './get-origins.js';
66
export { default as blobCache } from './blob-cache.js';
77
export { default as isViewableText } from './is-viewable-text.js';
88
export { default as isNumber } from './is-number.js';
9-
export { default as throwOutside } from './throw-outside.js';
109
export { default as parseBase64OrUint8Array } from './parse-base64-or-uint8array.js';
1110
export { default as emitError } from './emit-error.js';
1211
export { default as onPenumbraEvent } from './forward-events.js';

src/utils/throw-outside.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/zip.ts

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@ import { Writer } from '@transcend-io/conflux';
22
import mime from 'mime';
33
import { StreamSaverInstance } from './streamsaver.js';
44
import type { PenumbraFile, ZipOptions } from './types.js';
5-
import {
6-
isNumber,
7-
emitZipProgress,
8-
emitZipCompletion,
9-
throwOutside,
10-
} from './utils/index.js';
5+
import { isNumber, emitZipProgress, emitZipCompletion } from './utils/index.js';
116
import { logger } from './logger.js';
127

138
/**
@@ -34,11 +29,9 @@ const sumWrites = async (writes: Promise<number>[]): Promise<number> => {
3429
logger.error(error.reason, null);
3530
}
3631
// Throw AggregateError to console
37-
throwOutside(
38-
new AggregateError(
39-
errors,
40-
`File${errors.length > 1 ? 's' : ''} failed to be written to zip`,
41-
),
32+
throw new AggregateError(
33+
errors,
34+
`File${errors.length > 1 ? 's' : ''} failed to be written to zip`,
4235
);
4336
}
4437

@@ -66,7 +59,7 @@ export class PenumbraZipWriter extends EventTarget {
6659
private saveBuffer = false;
6760

6861
/** Zip buffer used for testing */
69-
private zipBuffer: Promise<ArrayBuffer> | undefined;
62+
private zipBufferPromise: Promise<ArrayBuffer> | undefined;
7063

7164
/** Allow & auto-rename duplicate files sent to writer */
7265
private allowDuplicates: boolean;
@@ -90,7 +83,7 @@ export class PenumbraZipWriter extends EventTarget {
9083
private bytesWritten = 0;
9184

9285
/** Promise representing completion of the zip stream piping to the file sink */
93-
private pipePromise?: Promise<void>;
86+
public pipePromise?: Promise<void>;
9487

9588
/**
9689
* Penumbra zip writer constructor
@@ -119,6 +112,7 @@ export class PenumbraZipWriter extends EventTarget {
119112
'abort',
120113
() => {
121114
this.close().catch((error: unknown) => {
115+
logger.error(error, null);
122116
logger.error(
123117
`Failed to close zip writer: ${error instanceof Error ? error.message : String(error)}`,
124118
null,
@@ -158,20 +152,34 @@ export class PenumbraZipWriter extends EventTarget {
158152
// keep the original promise's rejection for callers that await `done()`.
159153
// This is intentionally not chained to the `zipStream.pipeTo()` promise, so that `this.pipePromise` throws as normal.
160154
this.pipePromise.catch((error: unknown) => {
161-
const finalError =
155+
const asError =
162156
error instanceof Error
163157
? error
164158
: typeof error === 'string'
165159
? new Error(error)
166160
: new Error('Unknown error');
167-
finalError.message = `penumbra.saveZip() failed to create zip: ${finalError.message}`;
161+
const finalError = new Error(
162+
`penumbra.saveZip() failed to create zip: ${asError.message}`,
163+
);
168164
logger.error(finalError, null);
169165
});
170166

171167
// Buffer zip stream for debug & testing
172168
if (saveBuffer && bufferedZipStream) {
173169
this.saveBuffer = saveBuffer;
174-
this.zipBuffer = new Response(bufferedZipStream).arrayBuffer();
170+
this.zipBufferPromise = new Response(bufferedZipStream).arrayBuffer();
171+
this.zipBufferPromise.catch((error: unknown) => {
172+
const asError =
173+
error instanceof Error
174+
? error
175+
: typeof error === 'string'
176+
? new Error(error)
177+
: new Error('Unknown error');
178+
const finalError = new Error(
179+
`penumbra.saveZip() failed to buffer zip: ${asError.message}`,
180+
);
181+
logger.error(finalError, null);
182+
});
175183
}
176184
}
177185

@@ -255,7 +263,7 @@ export class PenumbraZipWriter extends EventTarget {
255263
null,
256264
);
257265
} else {
258-
zip.abort();
266+
zip.abort(new Error(warning));
259267
throw new Error(warning);
260268
}
261269
}
@@ -316,16 +324,19 @@ export class PenumbraZipWriter extends EventTarget {
316324
controller.close();
317325
reader.releaseLock();
318326
},
319-
cancel: (reason) => {
320-
const error =
327+
cancel: (reason: unknown) => {
328+
const asError =
321329
reason instanceof Error
322330
? reason
323331
: typeof reason === 'string'
324332
? new Error(reason)
325333
: new Error('Unknown error');
326334

327-
error.message = `penumbra.saveZip(): stream was cancelled: ${error.message}`;
328-
reject(error);
335+
const finalError = new Error(
336+
`penumbra.saveZip(): stream was cancelled: ${asError.message}`,
337+
);
338+
logger.error(finalError, null);
339+
reject(finalError);
329340
},
330341
});
331342

@@ -339,14 +350,17 @@ export class PenumbraZipWriter extends EventTarget {
339350
stream: () => completionTrackerStream,
340351
})
341352
.catch((error: unknown) => {
342-
const finalError =
353+
const asError =
343354
error instanceof Error
344355
? error
345356
: typeof error === 'string'
346357
? new Error(error)
347358
: new Error('Unknown error');
348359

349-
finalError.message = `penumbra.saveZip(): failed to write file ${filePath}: ${finalError.message}`;
360+
const finalError = new Error(
361+
`penumbra.saveZip(): failed to write file ${filePath}: ${asError.message}`,
362+
);
363+
logger.error(finalError, null);
350364
reject(finalError);
351365
});
352366
});
@@ -369,13 +383,16 @@ export class PenumbraZipWriter extends EventTarget {
369383
try {
370384
await this.writer.close();
371385
} catch (error: unknown) {
372-
const finalError =
386+
const asError =
373387
error instanceof Error
374388
? error
375389
: typeof error === 'string'
376390
? new Error(error)
377391
: new Error('Unknown error');
378-
finalError.message = `penumbra.saveZip(): failed to close zip writer: ${finalError.message}`;
392+
const finalError = new Error(
393+
`penumbra.saveZip(): failed to close zip writer: ${asError.message}`,
394+
);
395+
logger.error(finalError, null);
379396
throw finalError;
380397
}
381398
}
@@ -387,22 +404,25 @@ export class PenumbraZipWriter extends EventTarget {
387404
*/
388405
await this.pipePromise;
389406
} catch (error: unknown) {
390-
const finalError =
407+
const asError =
391408
error instanceof Error
392409
? error
393410
: typeof error === 'string'
394411
? new Error(error)
395412
: new Error('Unknown error');
396-
finalError.message = `penumbra.saveZip(): finished writing zip, but failed to download: ${finalError.message}`;
413+
const finalError = new Error(
414+
`penumbra.saveZip(): finished writing zip, but failed to download: ${asError.message}`,
415+
);
416+
logger.error(finalError, null);
397417
throw finalError;
398418
}
399419
return size;
400420
}
401421

402422
/** Cancel Penumbra zip writer */
403-
abort(): void {
423+
abort(reason?: Error): void {
404424
if (!this.controller.signal.aborted) {
405-
this.controller.abort();
425+
this.controller.abort(reason);
406426
}
407427
}
408428

@@ -416,12 +436,12 @@ export class PenumbraZipWriter extends EventTarget {
416436
'getBuffer() can only be called when a PenumbraZipWriter is closed',
417437
);
418438
}
419-
if (!this.saveBuffer || !this.zipBuffer) {
439+
if (!this.saveBuffer || !this.zipBufferPromise) {
420440
throw new Error(
421441
'getBuffer() can only be called on a PenumbraZipWriter in buffered mode, e.g. createZip({ saveBuffer: true })',
422442
);
423443
}
424-
return this.zipBuffer;
444+
return this.zipBufferPromise;
425445
}
426446

427447
/**

0 commit comments

Comments
 (0)