· MIT · Node.js 22.12+
Turn structured content into a readable PDF, editable Word document and portable Markdown—locally, from the same input.
Your research script or agent has produced useful text, tables and charts. Report Export Kit handles the delivery: define a small JSON document, keep its source references, and render three formats without rewriting the content. It is suitable for research notes, operational briefs and agent-generated reports that need to leave the chat window.
No model, account or API key is required. The renderer never fetches source URLs or sends report content to a service.
新增记录表格导出:读取调用者提供的版本快照,将长字段分段保留,并按文本写入单元格;详见下方接口说明。
New: exportRecordWorkbook(records) exports a supplied versioned snapshot to
XLSX (Records, Fields, Manifest). Each record needs id, version, and a JSON
fields object; optional source is caller-provided text. Run
node examples/records.js for a fictional long-text example. All user cells are
text, including = prefixes. Long fields split into ordered parts with JSON
Pointer paths; join them by record/version/path and numeric Part. No fetching or
latest-version substitution occurs. Limits: 1000 records, 50000 field parts,
10 MB input. Invalid XML characters are rejected. Output contains your supplied
data. This record API is separate from the three report-rendering formats below.
- Useful starting points
- Try a complete example
- The document contract
- Command-line use
- Start your own report from the included JSON
- Troubleshooting
- What the first release does well
- Scope and limitations
- Development
| Workflow | What you provide | What you can deliver |
|---|---|---|
| Research brief | Reviewed prose, observation tables and references | A readable PDF plus an editable Word copy |
| Weekly operations note | A stable JSON document produced by a script | The same content in three formats |
| Agent report delivery | Agent output mapped to validated blocks | Downloadable files with a source list and version |
The input remains your content: the exporter does not call a model to rewrite paragraphs, invent a chart interpretation or fetch linked evidence. This makes the rendering step easy to repeat and review separately from research and writing.
Requires Node.js 22.12+. In this project folder:
git clone https://github.com/workstonedai-collab/report-export-kit.git
cd report-export-kit
npm ci
npm run demoOpen output/demo.pdf, output/demo.docx and output/demo.md. The demo includes Chinese/English prose, a data table, a locally drawn PNG chart and an example source. All numbers and conclusions are invented. Markdown's chart is saved alongside it as figure-1.png.
The unmodified Noto Sans CJK SC font and its OFL license are included for Chinese PDF text. If the font is absent, npm run setup-font retrieves it from the official Noto repository. You can also pass your own compatible font using fontPath.
import { exportReport } from './src/index.js';
import fs from 'node:fs/promises';
const report = {
title: 'Weekly notes / 每周笔记', version: 1,
blocks: [
{ type: 'heading', text: 'Findings / 发现' },
{ type: 'paragraph', text: 'Your own reviewed content.' },
{ type: 'table', headers: ['Period', 'Value'], rows: [['2025', 12]] },
],
sources: [{ title: 'Your source', url: 'https://example.org/data' }],
};
const file = await exportReport(report, 'pdf');
await fs.writeFile('report.pdf', file.content);| Block | Required data | Notes |
|---|---|---|
heading |
text |
Optional level 1–3 |
paragraph |
text |
Plain text, including line breaks |
table |
headers, rows |
Every row must match header width; optional title/note |
image |
PNG base64 data |
Optional title/note; dimensions are read from PNG |
Top-level fields: title, optional positive integer version, subtitle, blocks, sources. Sources require a title and HTTP(S) URL, with optional publisher/date. They are a document reference list; this renderer does not establish claim-level evidence or verify the source.
For Markdown, write every returned assets item next to the .md file. exportReport also returns byte count, version and output SHA-256. The hash identifies a particular generated file; PDF metadata can make separately generated files differ.
node src/cli.js your-report.json outputThis writes report.pdf, report.docx, report.md and Markdown image assets. An optional third argument is a font path. The output directory is yours to manage; running again replaces the files with these fixed names.
A small editable input is included at examples/report.json. You can render it directly:
npm run export -- examples/report.json output/my-reportChange the title, paragraphs, rows and sources in a copy of that file, then run the same command with your file path. It writes three files named report.pdf, report.docx, report.md; a report with images also writes Markdown sidecar PNGs. Keep the .md and those images together when sharing them.
For library use, save each format and its image assets explicitly:
import fs from 'node:fs/promises';
import path from 'node:path';
import { exportReport } from './src/index.js';
const report = JSON.parse(await fs.readFile('examples/report.json', 'utf8'));
const directory = 'output/my-report';
await fs.mkdir(directory, { recursive: true });
for (const format of ['pdf', 'docx', 'md']) {
const result = await exportReport(report, format);
await fs.writeFile(path.join(directory, `report.${format}`), result.content);
for (const asset of result.assets) {
await fs.writeFile(path.join(directory, asset.filename), asset.content);
}
console.log(format, result.bytes, result.version, result.sha256);
}Use a different output directory per report when preserving history. A document version labels the supplied content; the library does not maintain a revision database.
For a PNG you already have, supply its base64 bytes in an image block:
const data = (await fs.readFile('your-chart.png')).toString('base64');
report.blocks.push({ type: 'image', data,
title: 'Your chart', note: 'State units, exact values and provenance here.' });The small barChart helper draws non-negative values locally. Add exact labels, units and values in a table or caption. Negative values, interactive plots and remote images are not supported by that helper; create a suitable PNG with your preferred chart tool instead.
To change the PDF font, pass exportReport(report, 'pdf', { fontPath: './your-font.ttf' }), or use the CLI's third argument. Use a font that covers every script in your text and whose terms permit your use. Word readers need a compatible font on the receiving computer.
| Symptom | What to check |
|---|---|
| Chinese PDF text fails or is missing | Confirm the bundled font exists or supply a compatible fontPath; npm run setup-font restores the official font if needed |
| A table is rejected | Every row must have exactly the same number of cells as headers; use finite numbers or strings |
| Markdown has a broken chart | Save the returned assets beside the Markdown, retaining their filenames |
| A source is rejected | Supply a title and a valid HTTP(S) URL |
| Word looks different from the PDF | It is a reflowable document; check local fonts and your office application's page layout |
| Output was replaced | The CLI uses fixed filenames; separate report versions into different directories |
- One validated document contract for three delivery formats.
- Chinese/English PDF text with an included open font.
- True Word tables and embedded PNG images.
- Multi-page PDF tables with repeated headers; large row content falls back to labeled paragraphs.
- Clear source references, versioned content and output hashes.
- A tiny local PNG bar-chart helper in
src/charts.js; exact labels, units and values belong in the adjacent table or caption.
This is a structured report renderer, not an arbitrary HTML/Markdown importer, office-template editor or document parser. PNG is the supported image format. Heading/paragraph blocks use plain text. Word's exact layout depends on the receiving office application and fonts; the font is referenced rather than embedded in DOCX. PDF output uses A4 pages and a simple editorial layout.
Validation catches malformed blocks and unsupported URLs; it does not validate factual accuracy. Review the source content before exporting. Large documents and images have bounded sizes. All processing is local, but the files you produce can contain whatever private content you supplied.
npm testTests cover three formats, input immutability, source/table validation and multi-page bilingual PDF output. The example PDF was also reopened for Chinese text/reference checks and visually rendered. CI is configured for Node 22/24 on three desktop OS families.
See THIRD-PARTY-NOTICES.md for the Noto font and dependencies, and CONTRIBUTING.md for contributions. Project code is licensed under MIT. Third-party dependencies and data retain their own terms.
