Skip to content

Instantly share code, notes, and snippets.

@danielrose7
Created October 10, 2025 00:25
Show Gist options
  • Save danielrose7/cd5e01f950477ff9b16444135c9293e9 to your computer and use it in GitHub Desktop.
Save danielrose7/cd5e01f950477ff9b16444135c9293e9 to your computer and use it in GitHub Desktop.
pdfMake getBase64 with promise with error handling
/**
* pdfMake's getBase64 provides for an async callback that does not allow for error handling (at least in v0.2.x)
* this recreates their OutputDocument.getBase64() behavior with accessible error handling
*/
export const generatePdfBase64 = (
pdf: TCreatedPdf,
{
endStream = true,
readChunkSize = 1024 * 1024 * 1024, // 1 GiB (matches pdfmake's OutputDocument.bufferSize)
timeoutMs = 15 * 1000,
}: GenerateOpts = {},
): Promise<string> => {
const stream = pdf.getStream();
return new Promise<string>((resolve, reject) => {
let settled = false;
const chunks: Buffer[] = [];
const settleReject = (err: unknown) => {
if (settled) return;
settled = true;
clearTimeout(timer);
cleanup();
reject(err instanceof Error ? err : new Error(String(err)));
};
const settleResolve = () => {
if (settled) return;
settled = true;
clearTimeout(timer);
cleanup();
try {
const buf = Buffer.concat(chunks);
resolve(buf.toString('base64'));
} catch (e) {
reject(e as Error);
}
};
const onReadable = () => {
let chunk;
// Pull mode for some streams
while ((chunk = stream.read(readChunkSize)) != null) {
const b = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
chunks.push(b);
}
};
const onEnd = () => settleResolve();
const onClose = () => {
if (!settled) settleReject(new Error('pdf stream closed before end'));
};
const onError = (err: unknown) => settleReject(err);
const cleanup = () => {
stream.off('readable', onReadable);
stream.off('end', onEnd);
stream.off('close', onClose);
stream.off('error', onError);
};
// Wire listeners BEFORE starting flow
stream.on('readable', onReadable);
stream.once('end', onEnd);
stream.once('close', onClose);
stream.once('error', onError);
const timer = setTimeout(() => {
settleReject(new Error('pdf stream timed out'));
}, timeoutMs);
// Mirror your OutputDocument.getBuffer() behavior
if (endStream && typeof stream.end === 'function') {
try {
stream.end();
} catch {
/* some error happened, swallow */
}
}
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment