@reportwright/engine 0.12.0 → 0.13.0

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +133 -1
  2. package/README.md +133 -12
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/index.js +6066 -4454
  5. package/dist/pdfstreamworker.js +2 -2
  6. package/dist/types/packages/engine/entry.d.ts +87 -5
  7. package/dist/types/src/engine/data/guard.d.ts +4 -1
  8. package/dist/types/src/engine/data/index.d.ts +14 -1
  9. package/dist/types/src/engine/expr/evaluate.d.ts +1 -0
  10. package/dist/types/src/engine/index.d.ts +11 -3
  11. package/dist/types/src/engine/items/chart-kit.d.ts +6 -0
  12. package/dist/types/src/engine/lazylibs.d.ts +46 -0
  13. package/dist/types/src/engine/notices.d.ts +1 -0
  14. package/dist/types/src/engine/options.d.ts +10 -0
  15. package/dist/types/src/engine/schema/report.schema.d.ts +3 -0
  16. package/dist/types/src/engine/stream.d.ts +32 -35
  17. package/dist/types/src/engine/text/fonts.d.ts +30 -5
  18. package/dist/types/src/engine/text/measure.d.ts +6 -0
  19. package/dist/types/src/engine/text/standard.d.ts +42 -0
  20. package/dist/types/src/exporters/docx.d.ts +19 -1
  21. package/dist/types/src/exporters/html.d.ts +9 -5
  22. package/dist/types/src/exporters/officestream.d.ts +27 -0
  23. package/dist/types/src/exporters/pdf.d.ts +5 -3
  24. package/dist/types/src/exporters/pdfpaint.d.ts +3 -11
  25. package/dist/types/src/exporters/pdfstandard.d.ts +23 -0
  26. package/dist/types/src/exporters/pdfstream.d.ts +16 -8
  27. package/dist/types/src/exporters/pdfstreamtags.d.ts +8 -1
  28. package/dist/types/src/exporters/spill.d.ts +20 -0
  29. package/dist/types/src/exporters/subset.d.ts +15 -0
  30. package/dist/types/src/exporters/xlsxstream.d.ts +22 -0
  31. package/examples/stream-1m.mjs +21 -8
  32. package/package.json +5 -3
  33. package/pool/worker.js +1 -1
  34. package/report.d.ts +1 -0
  35. package/schema.json +3 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Report definition → .docx written to sink as its pages are laid out.
3
+ * @param {any} def @param {any} opts render()'s options and exportDocx's (fontStore, fetchImage, figures, rasterize, lang,
4
+ * title), plus timeoutMs or deadline, signal, window (rows laid out at once), maxRows, sorter, sqlRows as exportPdfStream
5
+ * @param {Sink} sink not closed
6
+ * @returns {Promise<StreamResult>}
7
+ */
8
+ export function exportDocxStream(def: any, opts: any, sink: Sink): Promise<StreamResult>;
9
+ /**
10
+ * Report definition → .xlsx written to sink as its rows come.
11
+ * @param {any} def @param {any} opts render()'s options and exportXlsx's (currency, title, formulas, fontStore,
12
+ * fetchImage), plus timeoutMs or deadline, signal, maxRows, sorter, sqlRows as exportPdfStream
13
+ * @param {Sink} sink not closed
14
+ * @returns {Promise<StreamResult>}
15
+ */
16
+ export function exportXlsxStream(def: any, opts: any, sink: Sink): Promise<StreamResult>;
17
+ export type Sink = {
18
+ write(u8: Uint8Array): any;
19
+ once?: (ev: string, cb: () => void) => any;
20
+ };
21
+ export type StreamResult = {
22
+ streamed: boolean;
23
+ pages?: number;
24
+ rows?: number;
25
+ warnings: string[];
26
+ why?: string;
27
+ };
@@ -9,8 +9,10 @@
9
9
  * tagged?: { lang?: string }, drillBase?: string, onWarning?: (message: string) => void, timeoutMs?: number,
10
10
  * creationDate?: Date }} [opt]
11
11
  * subset: a HarfBuzz subsetter (see subset.js). Without it, fonts embed in full.
12
- * pdfa: make a PDF/A-2b file (needs an sRGB ICC profile). prepare: last change before saving
13
- * (the server adds a signature placeholder there). save: extra pdf-lib save options.
12
+ * pdfa: a PDF/A-2b file (2a with tagged): true uses the sRGB profile of @reportwright/fonts, or pass { icc } (this
13
+ * function itself needs icc; the engine package fills it in). prepare: last change to the pdf-lib PDFDocument before
14
+ * saving (the server adds a signature placeholder there). save: pdf-lib save options. These, encrypt and PDF/A without
15
+ * a profile take the whole-model path in exportPdfStream; a PDF/A file with a profile streams.
14
16
  * encrypt: { userPassword, ownerPassword, permissions } — AES-256 (see encrypt.js); not with pdfa or prepare.
15
17
  * tagged: an accessible PDF (PDF/UA-1, see pdfua.js): structure tree, marked content, artifacts, language, title
16
18
  * shown; with pdfa it is PDF/A-2a. Off, the file is exactly what it was.
@@ -42,4 +44,4 @@ export function exportPdf(model: any, fontStore: import("../engine/text/fonts.js
42
44
  timeoutMs?: number;
43
45
  creationDate?: Date;
44
46
  }): any;
45
- import { PDFDocument } from 'pdf-lib';
47
+ import { PDFDocument } from '../engine/lazylibs.js';
@@ -1,14 +1,4 @@
1
- /**
2
- * Draw one run of shaped glyphs by ID, where the engine placed them: a TJ array whose numbers move each
3
- * glyph from where the font's own advance (the W array) leaves it to the shaper's position; marks that sit
4
- * higher or lower use the text rise. /ActualText gives copy and search the characters: for a left-to-right
5
- * run the whole run in reading order; a right-to-left run (drawn in visual order, which readers reorder
6
- * themselves) reads through ToUnicode, glyph by glyph, and only a cluster ToUnicode cannot spell gets a span
7
- * (`spans`, from glyphText); glyphs that stand for nothing (`texts`: '') go last. A span per joined letter, and
8
- * the dots of joined letters drawn among the letters, made pdftotext split words ("الج ميل", "الت قن ية").
9
- * @param {Content} c @param {Set<number>} [spans] @param {Map<number, string>} [texts]
10
- */
11
- export function drawRun(c: Content, run: any, x: any, y: any, size: any, pf: any, color: any, spans?: Set<number>, texts?: Map<number, string>): void;
1
+ export function drawRun(c: any, run: any, x: any, y: any, size: any, pf: any, color: any, spans: any, texts: any): void;
12
2
  /**
13
3
  * The text each shaped glyph stands for, for the font's ToUnicode map: the character whose own (character-map)
14
4
  * glyph it is; the characters of its cluster that have no glyph of their own there (a conjunct, a joined
@@ -69,6 +59,8 @@ export class Content {
69
59
  /** straight lines waiting to be drawn after the text around them: { key, stroke, w, dash, segs: [x1, y1, x2, y2][] } */
70
60
  lines: any;
71
61
  tagged: boolean;
62
+ /** tagged, lines wait all the same and are drawn as one artifact (the streamed PDF's painter sets it) */
63
+ artLines: boolean;
72
64
  set s(v: string);
73
65
  /**
74
66
  * The operators so far. Any other drawing reads or appends to it, so the lines waiting are drawn first: the text
@@ -0,0 +1,23 @@
1
+ /** The font dictionary's entries (pdf-lib's context.obj takes them as they are: strings become names). @param {any} f a standard font */
2
+ export function standardFontEntries(f: any): {
3
+ FirstChar: number;
4
+ LastChar: number;
5
+ Widths: any;
6
+ Encoding?: string;
7
+ Type: string;
8
+ Subtype: string;
9
+ BaseFont: any;
10
+ };
11
+ /** The same dictionary as PDF syntax. @param {any} f */
12
+ export function standardFontDict(f: any): string;
13
+ /** A literal string's body: one byte per character, escaped. @param {any} f a standard font @param {string} text */
14
+ export function standardLiteral(f: any, text: string): string;
15
+ /**
16
+ * A page whose standard-font text is redrawn in the embedded stand-ins (PDF/A, PDF/UA), at the standard font's glyph
17
+ * positions. The page and the items it changes are copies; families gets the standard families it found.
18
+ * @param {any} pg @param {(key: string) => any} fontOf the loaded fonts by key @param {Set<string>} families
19
+ */
20
+ export function embeddedPage(pg: any, fontOf: (key: string) => any, families: Set<string>): any;
21
+ /** The warnings for the standard families a PDF/A or PDF/UA file drew in their stand-ins (a family's name is its regular face's key). @param {Set<string>} families */
22
+ export function embeddedWarnings(families: Set<string>): string[];
23
+ export function standIns(store: import("../engine/text/fonts.js").FontStore): string[];
@@ -1,16 +1,16 @@
1
1
  /**
2
- * @typedef {{ write(u8: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} Sink
3
- * write may return a promise (awaited: back-pressure), or false with a 'drain' event to wait for (a Node Writable).
4
- * @typedef {{ title: string, page: number, top?: number, level?: number }} OutlineEntry
5
- * page: 1-based; top: the destination's y in PDF space (from the bottom), else the page fits the window.
2
+ * p, or signal's reason as soon as it aborts (p goes on, unwatched).
3
+ * @template T @param {Promise<T>} p @param {AbortSignal} [signal] @returns {Promise<T>}
6
4
  */
5
+ export function raced<T>(p: Promise<T>, signal?: AbortSignal): Promise<T>;
7
6
  /**
8
7
  * @param {Sink} sink
9
8
  * @param {{ fontStore: import('../engine/text/fonts.js').FontStore, fonts?: string[],
10
9
  * subset?: (font: Uint8Array, codePoints: Iterable<number>, opt?: { glyphs?: Iterable<number> }) => Promise<Uint8Array>,
11
- * id?: string }} opt
10
+ * id?: string, signal?: AbortSignal }} opt
12
11
  * fonts: font keys to name now (F1, F2… in this order); any other font is named on first use.
13
12
  * subset: subset.js's subsetter; without it fonts embed in full. id: the file ID (32 hex digits), else random.
13
+ * signal: stops a wait for the sink (back-pressure) when it aborts.
14
14
  */
15
15
  export function createPdfStream(sink: Sink, opt: {
16
16
  fontStore: import("../engine/text/fonts.js").FontStore;
@@ -19,6 +19,7 @@ export function createPdfStream(sink: Sink, opt: {
19
19
  glyphs?: Iterable<number>;
20
20
  }) => Promise<Uint8Array>;
21
21
  id?: string;
22
+ signal?: AbortSignal;
22
23
  }): {
23
24
  /** @param {string} key @returns {string} the font's resource name (F1…) */
24
25
  fontName: (key: string) => string;
@@ -124,8 +125,12 @@ export function createPdfStream(sink: Sink, opt: {
124
125
  /**
125
126
  * A report to PDF bytes written to sink as its pages are laid out (planPaged: a flowing table, one window of rows at a
126
127
  * time), else rendered whole and exported by exportPdf, the same file it always was, written to sink in one piece.
127
- * opts: render()'s options and exportPdf's (fontStore, subset, title, author, creationDate, drillBase…). Tagged,
128
- * PDF/A, encrypted and signed files take the whole-model path.
128
+ * opts: render()'s options and exportPdf's (fontStore, subset, title, author, creationDate, drillBase…). Tagged
129
+ * (PDF/UA-1) and PDF/A files stream too; encrypted and signed files, save options and PDF/A without a colour profile
130
+ * take the whole-model path (the result's why says which).
131
+ * timeoutMs (or deadline) bounds the whole export, waits for the sink included; signal (an AbortSignal) stops it at its
132
+ * next wait (a row batch, the sink, a sort, a page). Stopped or failed: it rejects (the signal's reason, an AbortError;
133
+ * a timeout: status 504, code 'ETIMEDOUT'), the rows' cursors are closed, a sort's temporary files removed.
129
134
  * @param {any} def @param {any} opts @param {Sink} sink
130
135
  * @returns {Promise<{ streamed: boolean, pages: number, warnings: string[], why?: string }>}
131
136
  */
@@ -157,12 +162,13 @@ export function paintPage(pg: any, H: number, env: any): {
157
162
  };
158
163
  /**
159
164
  * What paintPage draws with: a writer's resource names and glyph records (w), the fonts, shaped glyphs' texts.
160
- * @param {any} w @param {any} fontStore @param {{ drillBase?: string, pageRef?: (i: number) => any, tags?: any }} [o]
165
+ * @param {any} w @param {any} fontStore @param {{ drillBase?: string, pageRef?: (i: number) => any, tags?: any, embedAll?: boolean }} [o]
161
166
  */
162
167
  export function paintEnv(w: any, fontStore: any, o?: {
163
168
  drillBase?: string;
164
169
  pageRef?: (i: number) => any;
165
170
  tags?: any;
171
+ embedAll?: boolean;
166
172
  }): {
167
173
  shared: {
168
174
  font: (f: any) => any;
@@ -179,6 +185,8 @@ export function paintEnv(w: any, fontStore: any, o?: {
179
185
  reserve: () => any;
180
186
  drillBase: string;
181
187
  tags: any;
188
+ /** PDF/A, PDF/UA: standard fonts drawn in embedded stand-ins; the families that were @type {Set<string>|null} */
189
+ embedded: Set<string> | null;
182
190
  };
183
191
  /**
184
192
  * write may return a promise (awaited: back-pressure), or false with a 'drain' event to wait for (a Node Writable).
@@ -5,11 +5,18 @@
5
5
  * ColSpan), Link > OBJR inside the element whose text it covers; page header and footer, borders and boxes artifacts.
6
6
  * Each page's rows (TR, TD), its parent-tree array and its links' elements are written when the page ends; what stays
7
7
  * is one number per row (the Table's kids) and two per page and link (the parent tree), written at the end.
8
+ * A cell's element is a few dozen bytes in an object stream (no /Type, which is optional; no /A on a plain TD): a
9
+ * million-row table has some 8 million of them, the most of the file's objects.
8
10
  */
9
11
  /**
10
12
  * @param {any} w the PDF writer (pdfstream.js createPdfStream)
13
+ * @param {{ maxElements?: number }} [o] maxElements: past it the export stops (413)
11
14
  */
12
- export function createStreamTagger(w: any): {
15
+ export function createStreamTagger(w: any, { maxElements }?: {
16
+ maxElements?: number;
17
+ }): {
18
+ /** structure elements so far */
19
+ readonly count: number;
13
20
  /** a new page (window: the paged window it came from; row ids are its own) @param {number} window */
14
21
  page(window: number): void;
15
22
  /**
@@ -0,0 +1,20 @@
1
+ /** At the server's start: remove the spill folders of processes that are gone (pw-spill-<pid>-…) and old-style ones. */
2
+ export function sweepAtBoot(root?: any): void;
3
+ export function spillSorter({ run, runBytes, frame, maxMB, totalMB, dir: root, staleMs }?: {
4
+ run?: number;
5
+ runBytes?: number;
6
+ frame?: number;
7
+ maxMB?: number;
8
+ totalMB?: number;
9
+ dir?: any;
10
+ staleMs?: number;
11
+ }): (cmp: (a: any, b: any) => number) => {
12
+ /** @param {any} r */
13
+ push(r: any): Promise<void>;
14
+ drain(): AsyncGenerator<any, void, unknown>;
15
+ close(): Promise<void>;
16
+ /** Tests: the runs written so far. */
17
+ readonly runs: number;
18
+ };
19
+ export function canSpill(): boolean;
20
+ export function spillShared(): any;
@@ -1,5 +1,20 @@
1
+ /**
2
+ * The tables of a single-face sfnt (TrueType or CFF) as a Map of tag to bytes. A collection (ttcf) gives an empty map.
3
+ * @param {Uint8Array} bytes
4
+ */
5
+ export function sfntTables(bytes: Uint8Array): Map<any, any>;
6
+ /** A sfnt from its tables: directory, 4-byte padding, table checksums and the head checkSumAdjustment. */
7
+ export function buildSfnt(version: any, tables: any): Uint8Array<ArrayBuffer>;
8
+ /**
9
+ * The name table with the given strings replaced (nameID to text). Each replaced string is written in its record's own
10
+ * encoding: UTF-16BE for Windows and Unicode, one byte per character for Macintosh.
11
+ * @param {Uint8Array} name
12
+ * @param {Map<number, string>} strings
13
+ */
14
+ export function setNameStrings(name: Uint8Array, strings: Map<number, string>): Uint8Array<ArrayBuffer>;
1
15
  /** @param {() => Promise<ArrayBuffer|Uint8Array>} loadWasm */
2
16
  export function createSubsetter(loadWasm: () => Promise<ArrayBuffer | Uint8Array>): (font: Uint8Array, codePoints: Iterable<number>, opt?: {
3
17
  glyphs?: Iterable<number>;
4
18
  layout?: boolean;
19
+ weight?: number;
5
20
  }) => Promise<Uint8Array>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @param {{ name: string, title: string, columns: number[], timeZone: string|null, locale: string|null, currency: string|null, rows: () => AsyncGenerator<any> }} plan
3
+ * @param {(bytes: Uint8Array) => any} put the zip's bytes as they come (awaited: back-pressure)
4
+ * @param {{ currency?: string, title?: string, formulas?: boolean, maxRows?: number, timeZone?: string }} [opt]
5
+ */
6
+ export function writeXlsxStream(plan: {
7
+ name: string;
8
+ title: string;
9
+ columns: number[];
10
+ timeZone: string | null;
11
+ locale: string | null;
12
+ currency: string | null;
13
+ rows: () => AsyncGenerator<any>;
14
+ }, put: (bytes: Uint8Array) => any, opt?: {
15
+ currency?: string;
16
+ title?: string;
17
+ formulas?: boolean;
18
+ maxRows?: number;
19
+ timeZone?: string;
20
+ }): Promise<void>;
21
+ export const EXCEL_ROWS: 1048576;
22
+ export const EXCEL_COLS: 16384;
@@ -4,13 +4,15 @@
4
4
  // cursor), so nothing holds them all.
5
5
  //
6
6
  // npm i @reportwright/engine @reportwright/fonts
7
- // node node_modules/@reportwright/engine/examples/stream-1m.mjs [rows=1000000] [out=ledger.pdf] [--plain] [--grouped] [--tagged] [--parallel=4]
7
+ // node node_modules/@reportwright/engine/examples/stream-1m.mjs [rows=1000000] [out=ledger.pdf] [--plain] [--grouped] [--presorted] [--tagged] [--array[=text]] [--parallel=N]
8
8
  //
9
9
  // Prints one JSON line: { rows, pages, streamed, peakRssMB, ms, bytes, ... }. "Page N of M" is in the page footer
10
10
  // (the rows are read twice: once to count the pages); --plain leaves M out (one pass). --grouped adds two group levels
11
- // with subtotals; --tagged makes an accessible PDF/A (PDF/UA-1 + PDF/A-2a); --parallel=N lays out and paints with N
12
- // worker threads. RW_ENGINE: import the engine from another path (a checkout: packages/engine/entry.js); RW_PUBLIC: a
13
- // folder with fonts/ and harfbuzz-subset.wasm instead of @reportwright/fonts.
11
+ // with subtotals (sorted through a disk spill; --presorted: the rows come in group order and are only checked); --tagged
12
+ // makes an accessible PDF/A (PDF/UA-1 + PDF/A-2a); --array: the rows as one array in the definition (--array=text: as
13
+ // JSON text); --parallel=N lays out and paints with N worker threads (serial by default: each thread costs 150-300 MB).
14
+ // RW_ENGINE: import the engine from another path (a checkout: packages/engine/entry.js); RW_PUBLIC: a folder with fonts/
15
+ // and harfbuzz-subset.wasm instead of @reportwright/fonts.
14
16
  import fs from 'node:fs';
15
17
  import path from 'node:path';
16
18
  import { pathToFileURL } from 'node:url';
@@ -33,13 +35,16 @@ if (process.env.RW_PUBLIC) {
33
35
  icc = fs.readFileSync(path.join(dir, 'icc', 'sRGB-v2-magic.icc'));
34
36
  }
35
37
 
38
+ const presorted = flag('presorted');
36
39
  const REGIONS = ['North', 'South', 'East', 'West'], TYPES = ['Deposit', 'Withdrawal', 'Transfer', 'Fee', 'Interest'];
37
40
  /** the rows, a thousand at a time, made as they are asked for */
38
41
  async function* rows() {
39
42
  for (let i = 0; i < N; i += 1000) {
40
43
  const batch = [];
41
44
  for (let j = i; j < Math.min(N, i + 1000); j++) {
42
- batch.push({ id: j + 1, account: `AC${String(10000 + (j * 7) % 9000)}`, region: REGIONS[(j >> 9) % 4], type: TYPES[(j >> 6) % 5],
45
+ // --presorted: the rows come in group order (as a query ordered by region, type gives them)
46
+ const region = presorted ? REGIONS[Math.floor(j * 4 / N)] : REGIONS[(j >> 9) % 4], type = presorted ? TYPES[Math.floor(j * 20 / N) % 5] : TYPES[(j >> 6) % 5];
47
+ batch.push({ id: j + 1, account: `AC${String(10000 + (j * 7) % 9000)}`, region, type,
43
48
  date: new Date(Date.UTC(2025, j % 12, 1 + (j % 28))), amount: Math.round(((j * 7919) % 200000 - 100000) * 1.37) / 100,
44
49
  reference: j % 37 === 0 ? `Reversal of an earlier transfer between linked accounts, batch ${j}` : `REF-${j * 31}` });
45
50
  }
@@ -78,10 +83,18 @@ const base = peak;
78
83
  const timer = setInterval(rss, 20);
79
84
  const t0 = Date.now();
80
85
  const out = fs.createWriteStream(file);
81
- const r = await exportPdfStream(def, { fonts, subset, title: 'Ledger', sqlRows: () => rows(), maxRows: Math.max(N, 5_000_000), timeoutMs: 24 * 3600e3,
86
+ // --array: the rows made first, one array in the report's JSON source (how a library caller often has them)
87
+ let arrayRssMB;
88
+ if (flag('array') || opt('array')) {
89
+ const all = [];
90
+ for await (const b of rows()) for (const x of b) all.push(x);
91
+ def.dataSources = [{ name: 'db', type: 'json', data: opt('array') === 'text' ? JSON.stringify(all) : all }];
92
+ rss(); arrayRssMB = Math.round(process.memoryUsage.rss() / 1048576);
93
+ }
94
+ const r = await exportPdfStream(def, { fonts, subset, title: 'Ledger', window: Number(opt('window')) || undefined, presorted, ...(flag('memsort') ? { spill: false } : {}), sqlRows: () => rows(), maxRows: Math.max(N, 5_000_000), timeoutMs: 24 * 3600e3,
82
95
  ...(flag('tagged') ? { tagged: { lang: 'en-IN' }, pdfa: icc ? { icc } : true } : {}), ...(opt('parallel') ? { parallel: Number(opt('parallel')) } : {}) }, out);
83
96
  await new Promise((ok, fail) => out.end((e) => (e ? fail(e) : ok())));
84
97
  clearInterval(timer);
85
98
  rss();
86
- console.log(JSON.stringify({ rows: N, pages: r.pages, streamed: r.streamed, ...(r.why ? { why: r.why } : {}), peakRssMB: Math.round(peak), startRssMB: Math.round(base), ms: Date.now() - t0,
87
- bytes: fs.statSync(file).size, file, node: process.version, grouped, tagged: flag('tagged'), parallel: Number(opt('parallel')) || 1 }));
99
+ console.log(JSON.stringify({ rows: N, pages: r.pages, streamed: r.streamed, ...(r.why ? { why: r.why } : {}), peakRssMB: Math.round(peak), startRssMB: Math.round(base), ...(arrayRssMB ? { arrayRssMB } : {}), ms: Date.now() - t0,
100
+ bytes: fs.statSync(file).size, file, node: process.version, grouped, presorted, tagged: flag('tagged'), parallel: Number(opt('parallel')) || 1 }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reportwright/engine",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -57,7 +57,8 @@
57
57
  "schema.json",
58
58
  "README.md",
59
59
  "CHANGELOG.md",
60
- "LICENSE"
60
+ "LICENSE",
61
+ "THIRD-PARTY-NOTICES.md"
61
62
  ],
62
63
  "engines": {
63
64
  "node": ">=20.9"
@@ -66,12 +67,13 @@
66
67
  "dependencies": {
67
68
  "pdf-lib": "1.17.1",
68
69
  "@pdf-lib/fontkit": "1.1.1",
70
+ "@pdf-lib/standard-fonts": "1.0.0",
69
71
  "bwip-js": "4.11.4",
70
72
  "fflate": "0.8.3",
71
73
  "bidi-js": "1.0.3"
72
74
  },
73
75
  "peerDependencies": {
74
- "@reportwright/fonts": "0.12.0"
76
+ "@reportwright/fonts": "0.13.0"
75
77
  },
76
78
  "peerDependenciesMeta": {
77
79
  "@reportwright/fonts": {
package/pool/worker.js CHANGED
@@ -10,7 +10,7 @@ const EXPORT = {
10
10
  xlsx: (m, o) => exportXlsx(m, { fonts, ...o }),
11
11
  docx: (m, o) => exportDocx(m, { fonts, ...o }),
12
12
  pptx: (m, o) => exportPptx(m, { fonts, ...o }),
13
- html: async (m, o) => new TextEncoder().encode(await exportHtml(m, fonts, o)),
13
+ html: async (m, o) => new TextEncoder().encode(await exportHtml(m, { ...o, fonts })),
14
14
  csv: async (m, o) => new TextEncoder().encode(exportCsv(m, o)),
15
15
  };
16
16
  /** @type {import('node:worker_threads').MessagePort} */ (parentPort).on('message', async ({ def, opts }) => {
package/report.d.ts CHANGED
@@ -344,6 +344,7 @@ export interface FormField extends ItemBase {
344
344
  type: 'field';
345
345
  kind?: 'text' | 'multiline' | 'checkbox' | 'choice';
346
346
  fieldName?: Expr<string>;
347
+ label?: Expr<string>;
347
348
  value?: Expr;
348
349
  options?: Expr;
349
350
  required?: boolean;
package/schema.json CHANGED
@@ -1259,6 +1259,9 @@
1259
1259
  "fieldName": {
1260
1260
  "x-ts": "Expr<string>"
1261
1261
  },
1262
+ "label": {
1263
+ "x-ts": "Expr<string>"
1264
+ },
1262
1265
  "value": {
1263
1266
  "x-ts": "Expr"
1264
1267
  },