av6-pdf-engine 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -293,7 +293,26 @@ interface RenderEnv {
293
293
  allowPageBreak: boolean;
294
294
  }
295
295
 
296
+ declare enum PdfEngineErrorCode {
297
+ PDF_ERROR_DEF_INVALID = "PDF_ERROR_DEF_INVALID",
298
+ PDF_ERROR_BLOCK_UNSUPPORTED = "PDF_ERROR_BLOCK_UNSUPPORTED",
299
+ PDF_ERROR_LAYOUT_INVALID = "PDF_ERROR_LAYOUT_INVALID",
300
+ PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW = "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW",
301
+ PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN = "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN",
302
+ PDF_ERROR_SIGNATURE_MISSING_BLOCKS = "PDF_ERROR_SIGNATURE_MISSING_BLOCKS",
303
+ PDF_ERROR_QR_GENERATION_FAILED = "PDF_ERROR_QR_GENERATION_FAILED",
304
+ PDF_ERROR_BARCODE_GENERATION_FAILED = "PDF_ERROR_BARCODE_GENERATION_FAILED",
305
+ PDF_ERROR_BARCODE_TYPE_UNSUPPORTED = "PDF_ERROR_BARCODE_TYPE_UNSUPPORTED",
306
+ PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH = "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH",
307
+ PDF_ERROR_IMAGE_SRC_INVALID = "PDF_ERROR_IMAGE_SRC_INVALID",
308
+ PDF_ERROR_IMAGE_FETCH_FAILED = "PDF_ERROR_IMAGE_FETCH_FAILED",
309
+ PDF_ERROR_FONT_REGISTER_FAILED = "PDF_ERROR_FONT_REGISTER_FAILED",
310
+ PDF_ERROR_OUTPUT_STREAM_ERROR = "PDF_ERROR_OUTPUT_STREAM_ERROR",
311
+ PDF_ERROR_RENDER_FAILED = "PDF_ERROR_RENDER_FAILED",
312
+ PDF_ERROR_PDFKIT_ERROR = "PDF_ERROR_PDFKIT_ERROR"
313
+ }
314
+
296
315
  declare function renderCustomPdf(def: CustomDocDefinition, outputPath: string): Promise<void>;
297
316
  declare function renderCustomPdfToBuffer(def: CustomDocDefinition): Promise<Buffer>;
298
317
 
299
- export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, renderCustomPdf, renderCustomPdfToBuffer };
318
+ export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineErrorCode, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, renderCustomPdf, renderCustomPdfToBuffer };
package/dist/index.d.ts CHANGED
@@ -293,7 +293,26 @@ interface RenderEnv {
293
293
  allowPageBreak: boolean;
294
294
  }
295
295
 
296
+ declare enum PdfEngineErrorCode {
297
+ PDF_ERROR_DEF_INVALID = "PDF_ERROR_DEF_INVALID",
298
+ PDF_ERROR_BLOCK_UNSUPPORTED = "PDF_ERROR_BLOCK_UNSUPPORTED",
299
+ PDF_ERROR_LAYOUT_INVALID = "PDF_ERROR_LAYOUT_INVALID",
300
+ PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW = "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW",
301
+ PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN = "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN",
302
+ PDF_ERROR_SIGNATURE_MISSING_BLOCKS = "PDF_ERROR_SIGNATURE_MISSING_BLOCKS",
303
+ PDF_ERROR_QR_GENERATION_FAILED = "PDF_ERROR_QR_GENERATION_FAILED",
304
+ PDF_ERROR_BARCODE_GENERATION_FAILED = "PDF_ERROR_BARCODE_GENERATION_FAILED",
305
+ PDF_ERROR_BARCODE_TYPE_UNSUPPORTED = "PDF_ERROR_BARCODE_TYPE_UNSUPPORTED",
306
+ PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH = "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH",
307
+ PDF_ERROR_IMAGE_SRC_INVALID = "PDF_ERROR_IMAGE_SRC_INVALID",
308
+ PDF_ERROR_IMAGE_FETCH_FAILED = "PDF_ERROR_IMAGE_FETCH_FAILED",
309
+ PDF_ERROR_FONT_REGISTER_FAILED = "PDF_ERROR_FONT_REGISTER_FAILED",
310
+ PDF_ERROR_OUTPUT_STREAM_ERROR = "PDF_ERROR_OUTPUT_STREAM_ERROR",
311
+ PDF_ERROR_RENDER_FAILED = "PDF_ERROR_RENDER_FAILED",
312
+ PDF_ERROR_PDFKIT_ERROR = "PDF_ERROR_PDFKIT_ERROR"
313
+ }
314
+
296
315
  declare function renderCustomPdf(def: CustomDocDefinition, outputPath: string): Promise<void>;
297
316
  declare function renderCustomPdfToBuffer(def: CustomDocDefinition): Promise<Buffer>;
298
317
 
299
- export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, renderCustomPdf, renderCustomPdfToBuffer };
318
+ export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineErrorCode, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, renderCustomPdf, renderCustomPdfToBuffer };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  BARCODE_TYPES: () => BARCODE_TYPES,
34
+ PdfEngineErrorCode: () => PdfEngineErrorCode,
34
35
  QR_ERROR_LEVEL: () => QR_ERROR_LEVEL,
35
36
  renderCustomPdf: () => renderCustomPdf,
36
37
  renderCustomPdfToBuffer: () => renderCustomPdfToBuffer
@@ -41,6 +42,44 @@ module.exports = __toCommonJS(index_exports);
41
42
  var import_fs = __toESM(require("fs"));
42
43
  var import_pdfkit = __toESM(require("pdfkit"));
43
44
 
45
+ // src/types/barcode.ts
46
+ var BARCODE_TYPES = {
47
+ CODE128: "CODE128",
48
+ EAN13: "EAN13",
49
+ CODE39: "CODE39",
50
+ ITF: "ITF",
51
+ CODE93: "CODE93"
52
+ };
53
+
54
+ // src/types/error.ts
55
+ var PdfEngineErrorCode = /* @__PURE__ */ ((PdfEngineErrorCode2) => {
56
+ PdfEngineErrorCode2["PDF_ERROR_DEF_INVALID"] = "PDF_ERROR_DEF_INVALID";
57
+ PdfEngineErrorCode2["PDF_ERROR_BLOCK_UNSUPPORTED"] = "PDF_ERROR_BLOCK_UNSUPPORTED";
58
+ PdfEngineErrorCode2["PDF_ERROR_LAYOUT_INVALID"] = "PDF_ERROR_LAYOUT_INVALID";
59
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW"] = "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW";
60
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN"] = "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN";
61
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_MISSING_BLOCKS"] = "PDF_ERROR_SIGNATURE_MISSING_BLOCKS";
62
+ PdfEngineErrorCode2["PDF_ERROR_QR_GENERATION_FAILED"] = "PDF_ERROR_QR_GENERATION_FAILED";
63
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_GENERATION_FAILED"] = "PDF_ERROR_BARCODE_GENERATION_FAILED";
64
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_TYPE_UNSUPPORTED"] = "PDF_ERROR_BARCODE_TYPE_UNSUPPORTED";
65
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH"] = "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH";
66
+ PdfEngineErrorCode2["PDF_ERROR_IMAGE_SRC_INVALID"] = "PDF_ERROR_IMAGE_SRC_INVALID";
67
+ PdfEngineErrorCode2["PDF_ERROR_IMAGE_FETCH_FAILED"] = "PDF_ERROR_IMAGE_FETCH_FAILED";
68
+ PdfEngineErrorCode2["PDF_ERROR_FONT_REGISTER_FAILED"] = "PDF_ERROR_FONT_REGISTER_FAILED";
69
+ PdfEngineErrorCode2["PDF_ERROR_OUTPUT_STREAM_ERROR"] = "PDF_ERROR_OUTPUT_STREAM_ERROR";
70
+ PdfEngineErrorCode2["PDF_ERROR_RENDER_FAILED"] = "PDF_ERROR_RENDER_FAILED";
71
+ PdfEngineErrorCode2["PDF_ERROR_PDFKIT_ERROR"] = "PDF_ERROR_PDFKIT_ERROR";
72
+ return PdfEngineErrorCode2;
73
+ })(PdfEngineErrorCode || {});
74
+
75
+ // src/types/qr.ts
76
+ var QR_ERROR_LEVEL = {
77
+ LOW: "L",
78
+ MEDIUM: "M",
79
+ QUARTILE: "Q",
80
+ HIGH: "H"
81
+ };
82
+
44
83
  // src/renderer-engine/blocks/barcode.ts
45
84
  var processBarcodeBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
46
85
  const imgSource = block.src;
@@ -711,10 +750,20 @@ function createBlockRenderer(deps) {
711
750
  );
712
751
  case "signature":
713
752
  if (!env.allowPageBreak) {
714
- throw new Error("Signature block is only allowed in main content flow.");
753
+ throw new PdfEngineError({
754
+ code: "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW" /* PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW */,
755
+ message: "Signature block is only allowed in main content flow.",
756
+ statusCode: 400,
757
+ details: { blockType: "signature" }
758
+ });
715
759
  }
716
760
  if (y !== null) {
717
- throw new Error("Signature block must be part of main flow, not drawn at explicit Y.");
761
+ throw new PdfEngineError({
762
+ code: "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN" /* PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN */,
763
+ message: "Signature block must be part of main flow, not drawn at explicit Y.",
764
+ statusCode: 400,
765
+ details: { blockType: "signature", y }
766
+ });
718
767
  }
719
768
  processSignatureBlock(block);
720
769
  return ctx.currentY;
@@ -776,6 +825,35 @@ var contentEnv = (doc) => ({
776
825
  allowPageBreak: true
777
826
  });
778
827
 
828
+ // src/renderer-engine/utils/error.ts
829
+ var PdfEngineError = class extends Error {
830
+ code;
831
+ statusCode;
832
+ details;
833
+ retryable;
834
+ cause;
835
+ constructor(args) {
836
+ super(args.message);
837
+ this.name = "PdfEngineError";
838
+ this.code = args.code;
839
+ this.statusCode = args.statusCode ?? 400;
840
+ this.details = args.details;
841
+ this.retryable = args.retryable ?? false;
842
+ this.cause = args.cause;
843
+ }
844
+ };
845
+ function toPdfEngineError(cause, fallback) {
846
+ if (cause instanceof PdfEngineError) return cause;
847
+ return new PdfEngineError({
848
+ code: fallback.code,
849
+ message: fallback.message,
850
+ statusCode: fallback.statusCode,
851
+ details: fallback.details,
852
+ retryable: fallback.retryable,
853
+ cause
854
+ });
855
+ }
856
+
779
857
  // src/renderer-engine/utils/finish-page.ts
780
858
  function finishPage({
781
859
  addNewPage,
@@ -922,10 +1000,18 @@ async function normalizeImageSrc(src) {
922
1000
  if (!src) return src;
923
1001
  if (Buffer.isBuffer(src)) return src;
924
1002
  if (src.startsWith("http://") || src.startsWith("https://")) {
925
- const res = await import_axios.default.get(src, {
926
- responseType: "arraybuffer"
927
- });
928
- return Buffer.from(res.data);
1003
+ try {
1004
+ const res = await import_axios.default.get(src, { responseType: "arraybuffer" });
1005
+ return Buffer.from(res.data);
1006
+ } catch (e) {
1007
+ throw toPdfEngineError(e, {
1008
+ code: "PDF_ERROR_IMAGE_FETCH_FAILED" /* PDF_ERROR_IMAGE_FETCH_FAILED */,
1009
+ message: "Failed to fetch remote image for PDF.",
1010
+ statusCode: 422,
1011
+ details: { url: src },
1012
+ retryable: false
1013
+ });
1014
+ }
929
1015
  }
930
1016
  return src;
931
1017
  }
@@ -939,9 +1025,7 @@ async function materializeImagesInBlocks(blocks) {
939
1025
  } else if (block.type === "columns") {
940
1026
  out.push({
941
1027
  ...block,
942
- columns: await Promise.all(
943
- block.columns.map((col) => materializeImagesInBlocks(col))
944
- )
1028
+ columns: await Promise.all(block.columns.map((col) => materializeImagesInBlocks(col)))
945
1029
  });
946
1030
  } else if (block.type === "signature" && block.blocks) {
947
1031
  out.push({
@@ -1290,7 +1374,15 @@ function generateQrBuffer(value, size, version, errorCorrectionLevel) {
1290
1374
  return new Promise((resolve, reject) => {
1291
1375
  import_qrcode.default.toBuffer(value, options, (err, buffer) => {
1292
1376
  if (err) {
1293
- return reject(err);
1377
+ return reject(
1378
+ toPdfEngineError(err, {
1379
+ code: "PDF_ERROR_QR_GENERATION_FAILED" /* PDF_ERROR_QR_GENERATION_FAILED */,
1380
+ message: "Failed to generate QR code.",
1381
+ statusCode: 500,
1382
+ details: { valuePreview: String(value).slice(0, 60), size },
1383
+ retryable: false
1384
+ })
1385
+ );
1294
1386
  }
1295
1387
  resolve(buffer);
1296
1388
  });
@@ -1312,13 +1404,7 @@ function mapBarcodeTypeToBcid(bcType) {
1312
1404
  }
1313
1405
  }
1314
1406
  function generateBarcodeBuffer(value, options = {}) {
1315
- const {
1316
- bcType,
1317
- scale = 3,
1318
- barHeight = 10,
1319
- includetext = false,
1320
- textalign = "center"
1321
- } = options;
1407
+ const { bcType, scale = 3, barHeight = 10, includetext = false, textalign = "center" } = options;
1322
1408
  const bcid = mapBarcodeTypeToBcid(bcType);
1323
1409
  return new Promise((resolve, reject) => {
1324
1410
  let textValue = value;
@@ -1327,12 +1413,16 @@ function generateBarcodeBuffer(value, options = {}) {
1327
1413
  if (digitsOnly.length === 13) {
1328
1414
  textValue = digitsOnly.slice(0, 12);
1329
1415
  } else if (digitsOnly.length === 12) {
1330
- textValue = textValue;
1416
+ textValue = digitsOnly;
1331
1417
  } else {
1332
1418
  return reject(
1333
- new Error(
1334
- `EAN13 barcode value must have 12 or 13 digits, got "${value}"`
1335
- )
1419
+ new PdfEngineError({
1420
+ code: "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH" /* PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH */,
1421
+ message: `EAN13 barcode value must have 12 or 13 digits, got "${value}"`,
1422
+ statusCode: 422,
1423
+ details: { value },
1424
+ retryable: false
1425
+ })
1336
1426
  );
1337
1427
  }
1338
1428
  }
@@ -1346,7 +1436,15 @@ function generateBarcodeBuffer(value, options = {}) {
1346
1436
  bwipOptions.textxalign = textalign;
1347
1437
  import_bwip_js.default.toBuffer(bwipOptions, (err, png) => {
1348
1438
  if (err) {
1349
- return reject(err);
1439
+ return reject(
1440
+ toPdfEngineError(err, {
1441
+ code: "PDF_ERROR_BARCODE_GENERATION_FAILED" /* PDF_ERROR_BARCODE_GENERATION_FAILED */,
1442
+ message: "Failed to generate barcode.",
1443
+ statusCode: 500,
1444
+ details: { bcType, valuePreview: String(value).slice(0, 60) },
1445
+ retryable: false
1446
+ })
1447
+ );
1350
1448
  }
1351
1449
  resolve(png);
1352
1450
  });
@@ -1380,12 +1478,7 @@ async function materializeQrAndBarcodesInBlocks(blocks) {
1380
1478
  const qb = { ...block };
1381
1479
  if (!qb.src && qb.value) {
1382
1480
  const size = qb.size ?? 80;
1383
- const buf = await generateQrBuffer(
1384
- qb.value,
1385
- size,
1386
- qb.qrVersion,
1387
- qb.errorCorrectionLevel
1388
- );
1481
+ const buf = await generateQrBuffer(qb.value, size, qb.qrVersion, qb.errorCorrectionLevel);
1389
1482
  qb.src = buf;
1390
1483
  }
1391
1484
  out.push(qb);
@@ -1659,9 +1752,7 @@ function drawWatermarkForPage(doc, watermark, pageNumber, isLast) {
1659
1752
  // src/renderer-engine/index.ts
1660
1753
  async function renderCustomPdf(def, outputPath) {
1661
1754
  if (def.header) {
1662
- def.header.blocks = await materializeQrAndBarcodesInBlocks(
1663
- def.header.blocks
1664
- );
1755
+ def.header.blocks = await materializeQrAndBarcodesInBlocks(def.header.blocks);
1665
1756
  def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
1666
1757
  }
1667
1758
  def.content = await materializeQrAndBarcodesInBlocks(def.content);
@@ -1670,9 +1761,7 @@ async function renderCustomPdf(def, outputPath) {
1670
1761
  def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
1671
1762
  }
1672
1763
  if (def.header?.backgroundImage) {
1673
- def.header.backgroundImage = await normalizeImageSrc(
1674
- def.header.backgroundImage
1675
- );
1764
+ def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage);
1676
1765
  }
1677
1766
  if (def.footer && typeof def.footer !== "function") {
1678
1767
  const footer = def.footer;
@@ -1751,14 +1840,23 @@ async function renderCustomPdf(def, outputPath) {
1751
1840
  finishPage2(false);
1752
1841
  doc.end();
1753
1842
  stream.on("finish", () => resolve());
1754
- stream.on("error", (err) => reject(err));
1843
+ stream.on(
1844
+ "error",
1845
+ (err) => reject(
1846
+ toPdfEngineError(err, {
1847
+ code: "PDF_ERROR_OUTPUT_STREAM_ERROR" /* PDF_ERROR_OUTPUT_STREAM_ERROR */,
1848
+ message: "Failed while writing PDF to output stream.",
1849
+ statusCode: 500,
1850
+ details: { outputPath },
1851
+ retryable: true
1852
+ })
1853
+ )
1854
+ );
1755
1855
  });
1756
1856
  }
1757
1857
  async function renderCustomPdfToBuffer(def) {
1758
1858
  if (def.header) {
1759
- def.header.blocks = await materializeQrAndBarcodesInBlocks(
1760
- def.header.blocks
1761
- );
1859
+ def.header.blocks = await materializeQrAndBarcodesInBlocks(def.header.blocks);
1762
1860
  def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
1763
1861
  }
1764
1862
  def.content = await materializeQrAndBarcodesInBlocks(def.content);
@@ -1767,9 +1865,7 @@ async function renderCustomPdfToBuffer(def) {
1767
1865
  def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
1768
1866
  }
1769
1867
  if (def.header?.backgroundImage) {
1770
- def.header.backgroundImage = await normalizeImageSrc(
1771
- def.header.backgroundImage
1772
- );
1868
+ def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage);
1773
1869
  }
1774
1870
  if (def.footer && typeof def.footer !== "function") {
1775
1871
  const footer = def.footer;
@@ -1797,7 +1893,14 @@ async function renderCustomPdfToBuffer(def) {
1797
1893
  resolve(Buffer.concat(chunks));
1798
1894
  });
1799
1895
  doc.on("error", (err) => {
1800
- reject(err);
1896
+ reject(
1897
+ toPdfEngineError(err, {
1898
+ code: "PDF_ERROR_PDFKIT_ERROR" /* PDF_ERROR_PDFKIT_ERROR */,
1899
+ message: "PDFKit emitted an error while rendering.",
1900
+ statusCode: 500,
1901
+ retryable: true
1902
+ })
1903
+ );
1801
1904
  });
1802
1905
  if (def.fonts && def.fonts.length) {
1803
1906
  for (const f of def.fonts) {
@@ -1857,26 +1960,10 @@ async function renderCustomPdfToBuffer(def) {
1857
1960
  doc.end();
1858
1961
  });
1859
1962
  }
1860
-
1861
- // src/types/barcode.ts
1862
- var BARCODE_TYPES = {
1863
- CODE128: "CODE128",
1864
- EAN13: "EAN13",
1865
- CODE39: "CODE39",
1866
- ITF: "ITF",
1867
- CODE93: "CODE93"
1868
- };
1869
-
1870
- // src/types/qr.ts
1871
- var QR_ERROR_LEVEL = {
1872
- LOW: "L",
1873
- MEDIUM: "M",
1874
- QUARTILE: "Q",
1875
- HIGH: "H"
1876
- };
1877
1963
  // Annotate the CommonJS export names for ESM import in node:
1878
1964
  0 && (module.exports = {
1879
1965
  BARCODE_TYPES,
1966
+ PdfEngineErrorCode,
1880
1967
  QR_ERROR_LEVEL,
1881
1968
  renderCustomPdf,
1882
1969
  renderCustomPdfToBuffer
package/dist/index.mjs CHANGED
@@ -2,6 +2,44 @@
2
2
  import fs from "fs";
3
3
  import PDFDocument from "pdfkit";
4
4
 
5
+ // src/types/barcode.ts
6
+ var BARCODE_TYPES = {
7
+ CODE128: "CODE128",
8
+ EAN13: "EAN13",
9
+ CODE39: "CODE39",
10
+ ITF: "ITF",
11
+ CODE93: "CODE93"
12
+ };
13
+
14
+ // src/types/error.ts
15
+ var PdfEngineErrorCode = /* @__PURE__ */ ((PdfEngineErrorCode2) => {
16
+ PdfEngineErrorCode2["PDF_ERROR_DEF_INVALID"] = "PDF_ERROR_DEF_INVALID";
17
+ PdfEngineErrorCode2["PDF_ERROR_BLOCK_UNSUPPORTED"] = "PDF_ERROR_BLOCK_UNSUPPORTED";
18
+ PdfEngineErrorCode2["PDF_ERROR_LAYOUT_INVALID"] = "PDF_ERROR_LAYOUT_INVALID";
19
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW"] = "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW";
20
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN"] = "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN";
21
+ PdfEngineErrorCode2["PDF_ERROR_SIGNATURE_MISSING_BLOCKS"] = "PDF_ERROR_SIGNATURE_MISSING_BLOCKS";
22
+ PdfEngineErrorCode2["PDF_ERROR_QR_GENERATION_FAILED"] = "PDF_ERROR_QR_GENERATION_FAILED";
23
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_GENERATION_FAILED"] = "PDF_ERROR_BARCODE_GENERATION_FAILED";
24
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_TYPE_UNSUPPORTED"] = "PDF_ERROR_BARCODE_TYPE_UNSUPPORTED";
25
+ PdfEngineErrorCode2["PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH"] = "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH";
26
+ PdfEngineErrorCode2["PDF_ERROR_IMAGE_SRC_INVALID"] = "PDF_ERROR_IMAGE_SRC_INVALID";
27
+ PdfEngineErrorCode2["PDF_ERROR_IMAGE_FETCH_FAILED"] = "PDF_ERROR_IMAGE_FETCH_FAILED";
28
+ PdfEngineErrorCode2["PDF_ERROR_FONT_REGISTER_FAILED"] = "PDF_ERROR_FONT_REGISTER_FAILED";
29
+ PdfEngineErrorCode2["PDF_ERROR_OUTPUT_STREAM_ERROR"] = "PDF_ERROR_OUTPUT_STREAM_ERROR";
30
+ PdfEngineErrorCode2["PDF_ERROR_RENDER_FAILED"] = "PDF_ERROR_RENDER_FAILED";
31
+ PdfEngineErrorCode2["PDF_ERROR_PDFKIT_ERROR"] = "PDF_ERROR_PDFKIT_ERROR";
32
+ return PdfEngineErrorCode2;
33
+ })(PdfEngineErrorCode || {});
34
+
35
+ // src/types/qr.ts
36
+ var QR_ERROR_LEVEL = {
37
+ LOW: "L",
38
+ MEDIUM: "M",
39
+ QUARTILE: "Q",
40
+ HIGH: "H"
41
+ };
42
+
5
43
  // src/renderer-engine/blocks/barcode.ts
6
44
  var processBarcodeBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
7
45
  const imgSource = block.src;
@@ -672,10 +710,20 @@ function createBlockRenderer(deps) {
672
710
  );
673
711
  case "signature":
674
712
  if (!env.allowPageBreak) {
675
- throw new Error("Signature block is only allowed in main content flow.");
713
+ throw new PdfEngineError({
714
+ code: "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW" /* PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW */,
715
+ message: "Signature block is only allowed in main content flow.",
716
+ statusCode: 400,
717
+ details: { blockType: "signature" }
718
+ });
676
719
  }
677
720
  if (y !== null) {
678
- throw new Error("Signature block must be part of main flow, not drawn at explicit Y.");
721
+ throw new PdfEngineError({
722
+ code: "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN" /* PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN */,
723
+ message: "Signature block must be part of main flow, not drawn at explicit Y.",
724
+ statusCode: 400,
725
+ details: { blockType: "signature", y }
726
+ });
679
727
  }
680
728
  processSignatureBlock(block);
681
729
  return ctx.currentY;
@@ -737,6 +785,35 @@ var contentEnv = (doc) => ({
737
785
  allowPageBreak: true
738
786
  });
739
787
 
788
+ // src/renderer-engine/utils/error.ts
789
+ var PdfEngineError = class extends Error {
790
+ code;
791
+ statusCode;
792
+ details;
793
+ retryable;
794
+ cause;
795
+ constructor(args) {
796
+ super(args.message);
797
+ this.name = "PdfEngineError";
798
+ this.code = args.code;
799
+ this.statusCode = args.statusCode ?? 400;
800
+ this.details = args.details;
801
+ this.retryable = args.retryable ?? false;
802
+ this.cause = args.cause;
803
+ }
804
+ };
805
+ function toPdfEngineError(cause, fallback) {
806
+ if (cause instanceof PdfEngineError) return cause;
807
+ return new PdfEngineError({
808
+ code: fallback.code,
809
+ message: fallback.message,
810
+ statusCode: fallback.statusCode,
811
+ details: fallback.details,
812
+ retryable: fallback.retryable,
813
+ cause
814
+ });
815
+ }
816
+
740
817
  // src/renderer-engine/utils/finish-page.ts
741
818
  function finishPage({
742
819
  addNewPage,
@@ -883,10 +960,18 @@ async function normalizeImageSrc(src) {
883
960
  if (!src) return src;
884
961
  if (Buffer.isBuffer(src)) return src;
885
962
  if (src.startsWith("http://") || src.startsWith("https://")) {
886
- const res = await axios.get(src, {
887
- responseType: "arraybuffer"
888
- });
889
- return Buffer.from(res.data);
963
+ try {
964
+ const res = await axios.get(src, { responseType: "arraybuffer" });
965
+ return Buffer.from(res.data);
966
+ } catch (e) {
967
+ throw toPdfEngineError(e, {
968
+ code: "PDF_ERROR_IMAGE_FETCH_FAILED" /* PDF_ERROR_IMAGE_FETCH_FAILED */,
969
+ message: "Failed to fetch remote image for PDF.",
970
+ statusCode: 422,
971
+ details: { url: src },
972
+ retryable: false
973
+ });
974
+ }
890
975
  }
891
976
  return src;
892
977
  }
@@ -900,9 +985,7 @@ async function materializeImagesInBlocks(blocks) {
900
985
  } else if (block.type === "columns") {
901
986
  out.push({
902
987
  ...block,
903
- columns: await Promise.all(
904
- block.columns.map((col) => materializeImagesInBlocks(col))
905
- )
988
+ columns: await Promise.all(block.columns.map((col) => materializeImagesInBlocks(col)))
906
989
  });
907
990
  } else if (block.type === "signature" && block.blocks) {
908
991
  out.push({
@@ -1251,7 +1334,15 @@ function generateQrBuffer(value, size, version, errorCorrectionLevel) {
1251
1334
  return new Promise((resolve, reject) => {
1252
1335
  QRCode.toBuffer(value, options, (err, buffer) => {
1253
1336
  if (err) {
1254
- return reject(err);
1337
+ return reject(
1338
+ toPdfEngineError(err, {
1339
+ code: "PDF_ERROR_QR_GENERATION_FAILED" /* PDF_ERROR_QR_GENERATION_FAILED */,
1340
+ message: "Failed to generate QR code.",
1341
+ statusCode: 500,
1342
+ details: { valuePreview: String(value).slice(0, 60), size },
1343
+ retryable: false
1344
+ })
1345
+ );
1255
1346
  }
1256
1347
  resolve(buffer);
1257
1348
  });
@@ -1273,13 +1364,7 @@ function mapBarcodeTypeToBcid(bcType) {
1273
1364
  }
1274
1365
  }
1275
1366
  function generateBarcodeBuffer(value, options = {}) {
1276
- const {
1277
- bcType,
1278
- scale = 3,
1279
- barHeight = 10,
1280
- includetext = false,
1281
- textalign = "center"
1282
- } = options;
1367
+ const { bcType, scale = 3, barHeight = 10, includetext = false, textalign = "center" } = options;
1283
1368
  const bcid = mapBarcodeTypeToBcid(bcType);
1284
1369
  return new Promise((resolve, reject) => {
1285
1370
  let textValue = value;
@@ -1288,12 +1373,16 @@ function generateBarcodeBuffer(value, options = {}) {
1288
1373
  if (digitsOnly.length === 13) {
1289
1374
  textValue = digitsOnly.slice(0, 12);
1290
1375
  } else if (digitsOnly.length === 12) {
1291
- textValue = textValue;
1376
+ textValue = digitsOnly;
1292
1377
  } else {
1293
1378
  return reject(
1294
- new Error(
1295
- `EAN13 barcode value must have 12 or 13 digits, got "${value}"`
1296
- )
1379
+ new PdfEngineError({
1380
+ code: "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH" /* PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH */,
1381
+ message: `EAN13 barcode value must have 12 or 13 digits, got "${value}"`,
1382
+ statusCode: 422,
1383
+ details: { value },
1384
+ retryable: false
1385
+ })
1297
1386
  );
1298
1387
  }
1299
1388
  }
@@ -1307,7 +1396,15 @@ function generateBarcodeBuffer(value, options = {}) {
1307
1396
  bwipOptions.textxalign = textalign;
1308
1397
  bwipjs.toBuffer(bwipOptions, (err, png) => {
1309
1398
  if (err) {
1310
- return reject(err);
1399
+ return reject(
1400
+ toPdfEngineError(err, {
1401
+ code: "PDF_ERROR_BARCODE_GENERATION_FAILED" /* PDF_ERROR_BARCODE_GENERATION_FAILED */,
1402
+ message: "Failed to generate barcode.",
1403
+ statusCode: 500,
1404
+ details: { bcType, valuePreview: String(value).slice(0, 60) },
1405
+ retryable: false
1406
+ })
1407
+ );
1311
1408
  }
1312
1409
  resolve(png);
1313
1410
  });
@@ -1341,12 +1438,7 @@ async function materializeQrAndBarcodesInBlocks(blocks) {
1341
1438
  const qb = { ...block };
1342
1439
  if (!qb.src && qb.value) {
1343
1440
  const size = qb.size ?? 80;
1344
- const buf = await generateQrBuffer(
1345
- qb.value,
1346
- size,
1347
- qb.qrVersion,
1348
- qb.errorCorrectionLevel
1349
- );
1441
+ const buf = await generateQrBuffer(qb.value, size, qb.qrVersion, qb.errorCorrectionLevel);
1350
1442
  qb.src = buf;
1351
1443
  }
1352
1444
  out.push(qb);
@@ -1620,9 +1712,7 @@ function drawWatermarkForPage(doc, watermark, pageNumber, isLast) {
1620
1712
  // src/renderer-engine/index.ts
1621
1713
  async function renderCustomPdf(def, outputPath) {
1622
1714
  if (def.header) {
1623
- def.header.blocks = await materializeQrAndBarcodesInBlocks(
1624
- def.header.blocks
1625
- );
1715
+ def.header.blocks = await materializeQrAndBarcodesInBlocks(def.header.blocks);
1626
1716
  def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
1627
1717
  }
1628
1718
  def.content = await materializeQrAndBarcodesInBlocks(def.content);
@@ -1631,9 +1721,7 @@ async function renderCustomPdf(def, outputPath) {
1631
1721
  def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
1632
1722
  }
1633
1723
  if (def.header?.backgroundImage) {
1634
- def.header.backgroundImage = await normalizeImageSrc(
1635
- def.header.backgroundImage
1636
- );
1724
+ def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage);
1637
1725
  }
1638
1726
  if (def.footer && typeof def.footer !== "function") {
1639
1727
  const footer = def.footer;
@@ -1712,14 +1800,23 @@ async function renderCustomPdf(def, outputPath) {
1712
1800
  finishPage2(false);
1713
1801
  doc.end();
1714
1802
  stream.on("finish", () => resolve());
1715
- stream.on("error", (err) => reject(err));
1803
+ stream.on(
1804
+ "error",
1805
+ (err) => reject(
1806
+ toPdfEngineError(err, {
1807
+ code: "PDF_ERROR_OUTPUT_STREAM_ERROR" /* PDF_ERROR_OUTPUT_STREAM_ERROR */,
1808
+ message: "Failed while writing PDF to output stream.",
1809
+ statusCode: 500,
1810
+ details: { outputPath },
1811
+ retryable: true
1812
+ })
1813
+ )
1814
+ );
1716
1815
  });
1717
1816
  }
1718
1817
  async function renderCustomPdfToBuffer(def) {
1719
1818
  if (def.header) {
1720
- def.header.blocks = await materializeQrAndBarcodesInBlocks(
1721
- def.header.blocks
1722
- );
1819
+ def.header.blocks = await materializeQrAndBarcodesInBlocks(def.header.blocks);
1723
1820
  def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
1724
1821
  }
1725
1822
  def.content = await materializeQrAndBarcodesInBlocks(def.content);
@@ -1728,9 +1825,7 @@ async function renderCustomPdfToBuffer(def) {
1728
1825
  def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
1729
1826
  }
1730
1827
  if (def.header?.backgroundImage) {
1731
- def.header.backgroundImage = await normalizeImageSrc(
1732
- def.header.backgroundImage
1733
- );
1828
+ def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage);
1734
1829
  }
1735
1830
  if (def.footer && typeof def.footer !== "function") {
1736
1831
  const footer = def.footer;
@@ -1758,7 +1853,14 @@ async function renderCustomPdfToBuffer(def) {
1758
1853
  resolve(Buffer.concat(chunks));
1759
1854
  });
1760
1855
  doc.on("error", (err) => {
1761
- reject(err);
1856
+ reject(
1857
+ toPdfEngineError(err, {
1858
+ code: "PDF_ERROR_PDFKIT_ERROR" /* PDF_ERROR_PDFKIT_ERROR */,
1859
+ message: "PDFKit emitted an error while rendering.",
1860
+ statusCode: 500,
1861
+ retryable: true
1862
+ })
1863
+ );
1762
1864
  });
1763
1865
  if (def.fonts && def.fonts.length) {
1764
1866
  for (const f of def.fonts) {
@@ -1818,25 +1920,9 @@ async function renderCustomPdfToBuffer(def) {
1818
1920
  doc.end();
1819
1921
  });
1820
1922
  }
1821
-
1822
- // src/types/barcode.ts
1823
- var BARCODE_TYPES = {
1824
- CODE128: "CODE128",
1825
- EAN13: "EAN13",
1826
- CODE39: "CODE39",
1827
- ITF: "ITF",
1828
- CODE93: "CODE93"
1829
- };
1830
-
1831
- // src/types/qr.ts
1832
- var QR_ERROR_LEVEL = {
1833
- LOW: "L",
1834
- MEDIUM: "M",
1835
- QUARTILE: "Q",
1836
- HIGH: "H"
1837
- };
1838
1923
  export {
1839
1924
  BARCODE_TYPES,
1925
+ PdfEngineErrorCode,
1840
1926
  QR_ERROR_LEVEL,
1841
1927
  renderCustomPdf,
1842
1928
  renderCustomPdfToBuffer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "av6-pdf-engine",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.mjs",
@@ -14,17 +14,19 @@
14
14
  "format": "prettier --write **/*.ts"
15
15
  },
16
16
  "dependencies": {
17
+ "@types/pdfkit": "^0.13.6",
17
18
  "axios": "^1.13.2",
18
19
  "bwip-js": "^4.8.0",
19
20
  "pdfkit": "^0.15.0",
20
21
  "qrcode": "^1.5.4",
21
- "tsup": "^8.5.1",
22
- "@types/pdfkit": "^0.13.6"
22
+ "tsup": "^8.5.1"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/bwip-js": "^3.2.3",
26
+ "@types/node": "^24.10.1",
26
27
  "@types/qrcode": "^1.5.6",
27
- "typescript": "^5.4.0",
28
- "prettier": "^3.6.2"
29
- }
28
+ "prettier": "^3.6.2",
29
+ "typescript": "^5.4.0"
30
+ },
31
+ "packageManager": "pnpm@10.8.1+sha512.c50088ba998c67b8ca8c99df8a5e02fd2ae2e2b29aaf238feaa9e124248d3f48f9fb6db2424949ff901cffbb5e0f0cc1ad6aedb602cd29450751d11c35023677"
30
32
  }