@reportwright/engine 0.12.0 → 0.12.1

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.
@@ -49,10 +49,14 @@ export function exportPptx(model: any, options?: NonNullable<Parameters<typeof e
49
49
  fonts?: FontStore;
50
50
  }, ...args: any[]): Promise<Uint8Array>;
51
51
  /**
52
- * @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string },
53
- * window?: number, parallel?: number, maxRows?: number, id?: string }} PdfStreamOptions
52
+ * @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string, maxElements?: number },
53
+ * window?: number, parallel?: number, maxRows?: number, id?: string, presorted?: boolean,
54
+ * spill?: false | { dir?: string, maxMB?: number }, sorter?: (cmp: (a: any, b: any) => number) => any }} PdfStreamOptions
54
55
  * render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
55
- * that lay out and paint pages, opt-in; the file is the same), maxRows (rows read, 5,000,000), id (the file ID).
56
+ * that lay out and paint pages, opt-in; the file is the same, each thread costs memory), maxRows (rows read,
57
+ * 5,000,000), id (the file ID). presorted: the rows come in the report's order (its sort, its groups together), so
58
+ * they are not sorted, only checked as they pass (a row out of order stops the export). spill: where a sort's runs go
59
+ * (Node: the system temp folder, 2 GB at most; false sorts in memory); in a browser a sort is in memory.
56
60
  */
57
61
  /**
58
62
  * Report definition → PDF written to a sink as it is made, for reports too large to hold as a page model: a flowing
@@ -95,17 +99,27 @@ export type PdfOptions = Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>,
95
99
  };
96
100
  /**
97
101
  * render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
98
- * that lay out and paint pages, opt-in; the file is the same), maxRows (rows read, 5,000,000), id (the file ID).
102
+ * that lay out and paint pages, opt-in; the file is the same, each thread costs memory), maxRows (rows read,
103
+ * 5,000,000), id (the file ID). presorted: the rows come in the report's order (its sort, its groups together), so
104
+ * they are not sorted, only checked as they pass (a row out of order stops the export). spill: where a sort's runs go
105
+ * (Node: the system temp folder, 2 GB at most; false sorts in memory); in a browser a sort is in memory.
99
106
  */
100
107
  export type PdfStreamOptions = RenderOptions & Omit<PdfOptions, "fonts"> & {
101
108
  fonts?: FontStore;
102
109
  tagged?: {
103
110
  lang?: string;
111
+ maxElements?: number;
104
112
  };
105
113
  window?: number;
106
114
  parallel?: number;
107
115
  maxRows?: number;
108
116
  id?: string;
117
+ presorted?: boolean;
118
+ spill?: false | {
119
+ dir?: string;
120
+ maxMB?: number;
121
+ };
122
+ sorter?: (cmp: (a: any, b: any) => number) => any;
109
123
  };
110
124
  export type RenderOptions = import("../../src/engine/index.js").RenderOptions;
111
125
  import { FontStore } from '../../src/engine/index.js';
@@ -16,11 +16,14 @@ export function redirectRequest(from: URL, to: URL, req: any, status: number): a
16
16
  /**
17
17
  * The guarded default fetch (see the top of this file). In Node every hop goes through nodeRequest (address pinned);
18
18
  * in a browser through `base` with redirects by hand (literal addresses checked; a browser has no DNS to ask).
19
- * @param {{ allowHosts?: string[] }} opt @param {typeof fetch} base
19
+ * @param {{ allowHosts?: string[], viaBase?: boolean }} opt viaBase: every hop through `base`, in Node too (the browser
20
+ * viewer's fetch, which its tests run in Node)
21
+ * @param {typeof fetch} base
20
22
  * @returns {typeof fetch}
21
23
  */
22
24
  export function guardedFetch(opt: {
23
25
  allowHosts?: string[];
26
+ viaBase?: boolean;
24
27
  }, base: typeof fetch): typeof fetch;
25
28
  /**
26
29
  * Any fetch with the engine's time limit and byte cap.
@@ -71,7 +71,7 @@ export class ReportError extends Error {
71
71
  }
72
72
  export const BAND_ITEMS: 250000;
73
73
  /** The start of the warning for CJK text without the optional CJK fonts (the viewer opens its warnings for it). */
74
- export const NO_CJK_FONTS: "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm run fonts:cjk";
74
+ export const NO_CJK_FONTS: "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm i @reportwright/fonts-cjk, then npx reportwright-fonts-cjk (npm); in the app, npm run fonts:cjk";
75
75
  /**
76
76
  * Options for render(). All optional.
77
77
  */
@@ -10,6 +10,12 @@ export function niceScale(min: any, max: any, ticks?: number): {
10
10
  hi: number;
11
11
  step: number;
12
12
  };
13
+ /** A nice scale whose step is the span over the ticks: niceScale rounds the span first, which can add a whole step. */
14
+ export function niceScaleSpan(min: any, max: any, ticks?: number): {
15
+ lo: number;
16
+ hi: number;
17
+ step: number;
18
+ };
13
19
  /** Ticks from lo to hi by step, rounded so 0.1 + 0.2 reads 0.3. At most 200 (a bad min/max cannot loop for ever). */
14
20
  export function linearTicks(lo: any, hi: any, step: any): any[];
15
21
  /** Powers of ten covering [min, max] (both > 0); at least two. */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (server/spill.js).
2
+ * An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (exporters/spill.js; exportPdfStream's default in Node).
3
3
  * @param {(a: any, b: any) => number} cmp
4
4
  */
5
5
  export function memorySorter(cmp: (a: any, b: any) => number): {
@@ -11,9 +11,9 @@ export function memorySorter(cmp: (a: any, b: any) => number): {
11
11
  * @param {any} def0 the report definition
12
12
  * @param {{ format: 'csv'|'xlsx', parameters?: object, timeZone?: string, now?: Date, state?: any, loadReport?: (id: string) => Promise<any>,
13
13
  * reportId?: string, fetch?: typeof fetch, baseUrl?: string, sql?: (src: any, p: any) => Promise<object[]>,
14
- * sqlRows?: (src: any, p: any) => AsyncIterable<object[]>, sources?: Record<string, any>, sorter?: (cmp: (a: any, b: any) => number) => any,
14
+ * sqlRows?: (src: any, p: any) => AsyncIterable<object[]>, sources?: Record<string, any>, sorter?: (cmp: (a: any, b: any) => number) => any, presorted?: boolean,
15
15
  * deadline?: number, timeoutMs?: number, maxRows?: number, maxJsonRowBytes?: number, maxJsonWholeBytes?: number }} opts
16
- * @returns {Promise<{ why: string } | { why?: undefined, name: string, columns: number[], title: string, timeZone: string|null, locale: string|null, currency: string|null, warnings: string[], rows: () => AsyncGenerator<any>, records: () => AsyncGenerator<any>, grouped: () => AsyncGenerator<any>, stats: { rows: number } }>}
16
+ * @returns {Promise<{ why: string } | { why?: undefined, name: string, columns: number[], title: string, timeZone: string|null, locale: string|null, currency: string|null, warnings: string[], rows: () => AsyncGenerator<any>, records: () => AsyncGenerator<any>, grouped: () => AsyncGenerator<any>, fieldList: () => Promise<any[]>, stats: { rows: number } }>}
17
17
  */
18
18
  export function planStream(def0: any, opts: {
19
19
  format: "csv" | "xlsx";
@@ -29,6 +29,7 @@ export function planStream(def0: any, opts: {
29
29
  sqlRows?: (src: any, p: any) => AsyncIterable<object[]>;
30
30
  sources?: Record<string, any>;
31
31
  sorter?: (cmp: (a: any, b: any) => number) => any;
32
+ presorted?: boolean;
32
33
  deadline?: number;
33
34
  timeoutMs?: number;
34
35
  maxRows?: number;
@@ -48,6 +49,7 @@ export function planStream(def0: any, opts: {
48
49
  rows: () => AsyncGenerator<any>;
49
50
  records: () => AsyncGenerator<any>;
50
51
  grouped: () => AsyncGenerator<any>;
52
+ fieldList: () => Promise<any[]>;
51
53
  stats: {
52
54
  rows: number;
53
55
  };
@@ -19,6 +19,8 @@ export function saBreaks(text: string, segmenter?: Intl.Segmenter | null): Set<n
19
19
  * @param {any[]} items @param {TextMeasurer} m
20
20
  */
21
21
  export function finishText(items: any[], m: TextMeasurer): void;
22
+ /** Unicode format characters (Cf): bidi marks and embeddings, joiners, soft hyphen. They have no shape of their own. */
23
+ export const FORMAT_CHAR: RegExp;
22
24
  /**
23
25
  * @typedef {{ font: string, x: number, w: number, text: string, rtl?: boolean, shaped?: boolean, glyphs: number[] }} Run
24
26
  * One font, one direction. x and w in points from the start of the line; glyphs: [id, x, y, cluster] per glyph
@@ -1,9 +1,12 @@
1
+ /** The string cut into pieces of at most about max chars, each ending at a '>' (a tag boundary), so their join is s. */
2
+ export function slices(s: any, max: any): any[];
1
3
  /** Left, right or centre, from where the lines sit in their box. */
2
4
  export function alignOf(it: any): "center" | "left" | "right" | "both";
3
5
  /**
4
6
  * @param {any} model render() output
5
7
  * @param {{ title?: string, author?: string, lang?: string, fontStore?: any, fetchImage?: (src: string) => Promise<Uint8Array|null>,
6
- * rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array|null>, figures?: boolean }} [opt]
8
+ * rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array|null>, figures?: boolean, xmlChunk?: number }} [opt]
9
+ * xmlChunk: the document XML is written to the zip in pieces of about this many chars (default 4M; tests lower it)
7
10
  * fontStore: text in pictures as outlines (else the reader's fallback font); fetchImage: pictures by URL;
8
11
  * rasterize: the PNG fallback of a picture (default: a canvas in a browser, sharp in Node); figures: false leaves them out.
9
12
  * @returns {Promise<Uint8Array>}
@@ -16,4 +19,5 @@ export function exportDocx(model: any, opt?: {
16
19
  fetchImage?: (src: string) => Promise<Uint8Array | null>;
17
20
  rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array | null>;
18
21
  figures?: boolean;
22
+ xmlChunk?: number;
19
23
  }): Promise<Uint8Array>;
@@ -4,12 +4,15 @@
4
4
  * drill-through opens the ReportWright viewer at drillBase (without one it is shown disabled).
5
5
  * Unless static, a file whose report has tables also gets a Tables view (htmldata.js): the tables as HTML, re-sorted on
6
6
  * their interactive-sort columns, groups opened and closed, rows filtered, by one inline script the file's CSP allows.
7
+ * exportHtml(model, { fonts, ...options }). The 0.7 form exportHtml(model, fontStore, options) still works (deprecated).
7
8
  * @param {any} model
8
- * @param {import('../engine/text/fonts.js').FontStore} fontStore
9
- * @param {{ title?: string, drillBase?: string, subset?: (font: Uint8Array, cps: Iterable<number>, o?: { layout?: boolean }) => Promise<Uint8Array>,
10
- * static?: boolean, locale?: string, currency?: string, lang?: string, strings?: Partial<typeof DATA_STRINGS> }} [opt]
9
+ * @param {{ fonts?: import('../engine/text/fonts.js').FontStore, fontStore?: import('../engine/text/fonts.js').FontStore, title?: string, drillBase?: string, subset?: (font: Uint8Array, cps: Iterable<number>, o?: { layout?: boolean }) => Promise<Uint8Array>,
10
+ * static?: boolean, locale?: string, currency?: string, lang?: string, strings?: Partial<typeof DATA_STRINGS>, timeoutMs?: number } | import('../engine/text/fonts.js').FontStore} [options]
11
+ * @param {any} [legacyOpt] the options of the 0.7 form
11
12
  */
12
- export function exportHtml(model: any, fontStore: import("../engine/text/fonts.js").FontStore, opt?: {
13
+ export function exportHtml(model: any, options?: {
14
+ fonts?: import("../engine/text/fonts.js").FontStore;
15
+ fontStore?: import("../engine/text/fonts.js").FontStore;
13
16
  title?: string;
14
17
  drillBase?: string;
15
18
  subset?: (font: Uint8Array, cps: Iterable<number>, o?: {
@@ -20,5 +23,6 @@ export function exportHtml(model: any, fontStore: import("../engine/text/fonts.j
20
23
  currency?: string;
21
24
  lang?: string;
22
25
  strings?: Partial<typeof DATA_STRINGS>;
23
- }): any;
26
+ timeoutMs?: number;
27
+ } | import("../engine/text/fonts.js").FontStore, legacyOpt?: any): Promise<string>;
24
28
  import { DATA_STRINGS } from './htmldata.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
@@ -124,8 +124,9 @@ export function createPdfStream(sink: Sink, opt: {
124
124
  /**
125
125
  * 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
126
  * 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.
127
+ * opts: render()'s options and exportPdf's (fontStore, subset, title, author, creationDate, drillBase…). Tagged
128
+ * (PDF/UA-1) and PDF/A files stream too; encrypted and signed files, save options and PDF/A without a colour profile
129
+ * take the whole-model path (the result's why says which).
129
130
  * @param {any} def @param {any} opts @param {Sink} sink
130
131
  * @returns {Promise<{ streamed: boolean, pages: number, warnings: string[], why?: string }>}
131
132
  */
@@ -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;
@@ -2,4 +2,5 @@
2
2
  export function createSubsetter(loadWasm: () => Promise<ArrayBuffer | Uint8Array>): (font: Uint8Array, codePoints: Iterable<number>, opt?: {
3
3
  glyphs?: Iterable<number>;
4
4
  layout?: boolean;
5
+ weight?: number;
5
6
  }) => Promise<Uint8Array>;
@@ -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.12.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -71,7 +71,7 @@
71
71
  "bidi-js": "1.0.3"
72
72
  },
73
73
  "peerDependencies": {
74
- "@reportwright/fonts": "0.12.0"
74
+ "@reportwright/fonts": "0.12.1"
75
75
  },
76
76
  "peerDependenciesMeta": {
77
77
  "@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 }) => {