Changelog
1.2.2
@xlvane/mcp
- The name for the official MCP Registry is
io.github.DevXord/xlvane(mcpNameandserver.json): the registry compares the namespace with case, and the lower-case name of 1.2.1 was refused. No change in behaviour.
All packages
- The release workflow stages each package unless its version is already on npm, and goes on after a failed package, so a repeated run finishes the release. No change in the packages themselves.
1.2.1
@xlvane/mcp
package.jsonhasmcpName(io.github.devxord/xlvane), andpackages/mcp/server.jsondescribes the server for the official MCP Registry, so the server can be listed there. No change in behaviour.
xlvane, @xlvane/compat
- No changes besides the version.
1.2.0
@xlvane/mcp (new)
- An MCP (Model Context Protocol) server for XLSX files, on the official MCP TypeScript SDK (
@modelcontextprotocol/server2.4.0, protocol revision 2026-07-28), over stdio:- start it with
npx @xlvane/mcp --root ./dataorxlvane mcp --root ./data; inspect_workbook,read_table,diffandvalidateare always available;write_table,edit_cellsandconvertonly with--allow-write.
- start it with
- Directories: files are read and written only inside the
--rootdirectories, after symbolic links are resolved. A file is checked again after it is opened. Writes never replace a file without"overwrite": true. - Limits:
- files above
--max-file-size(default 64 MiB) are refused; - a tool result is at most
--max-response-chars(default 1 Mi characters of JSON):read_tablereturns the rows that fit, withnextOffset; validatelists at most 1 000 problems.
- files above
- Errors: tool errors carry the
XlvErrorcode, location and hint. - API:
createServer()andrunCli()for other transports and tests.
xlvane
- The command
xlvane mcpstarts the server from@xlvane/mcp(a separate package), and prints how to install it when it is missing (XLV_E_NOT_INSTALLED). The error codeXLV_E_PATH_NOT_ALLOWEDis used by the server. - The Agent Skill describes the MCP server.
- Fix: the streaming reader (
openWorkbookStream,readTableStream) could refuse a valid file with "Comment is longer than the limit" (1.1.1). This happened when the--that ends an XML comment was the last thing in one piece of decompressed data and more thanmaxXmlTextLength(8 Mi characters) of the part followed without another--. It was found by fuzzing.
@xlvane/compat
- No changes besides the version.
1.1.1
A security release: small, crafted files could make reading, converting or the command line take minutes or run out of memory. Upgrading is recommended for everyone who opens files from untrusted sources. No API changes besides two new warning codes.
Security
- Output budgets:
toCSV,readTable,toJSON,readTableStream,xlvane readandxlvane convertwrite at mostmax(maxCells, 16 × cells read)positions; beyond that they throwXLV_E_LIMIT_EXCEEDED(details.limitmaxCells). Before, two cells A1 and XFD1048576 madetoCSVwrite billions of empty fields, and a header 16 384 columns wide madereadTablebuild 16 384 properties per cell. Pass a smallerrangeto read part of a large sheet. - Shared formulas: the text of cells sharing a formula counts against
maxSharedStringChars(the length of each cell's moved formula, apart from shared strings). Before, a 13 KB file sharing a 1 MiB formula with 2 000 cells took about 2 GB once the formulas were read. - Sheets sharing one part: a worksheet part used by several sheets is read once; the other sheets are returned without cells and with the new warning
XLV_W_SHEET_PART_SHARED. The same holds for comments, VML and table parts (the other sheets are read without those notes or tables). Before, such a part was decompressed and parsed once per sheet, outside the limit on decompressed bytes. - Hyperlinks: linking hyperlinks to cells is limited; beyond the limit
cell.hyperlinkis not set, with the new warningXLV_W_LIMIT_REACHED(sheet.hyperlinkslists every link). - Linear time: the streaming XML parser on long comments, attributes or text arriving in many pieces; opening a ZIP archive from a
Blobwith many entries;insertRows/deleteRowson sheets with comments holding<drawing; rows of style-only cells written right to left. Repeated header names inreadTable,toJSON,readTableStreamandxlvane read(16 384 columns namedx: 12 s before). XML comments and processing instructions longer thanmaxXmlTextLengthare refused, as text is; the streaming reader also stops early on an unfinished CDATA section, attribute value, reference or XML declaration that is already too long. insertRows/deleteRowsno longer take adrawingelement inside an XML comment for the sheet's drawing.- Command line: text from files is escaped also when colours are on: before, an escape sequence that looked like one of the command line's colours passed through (for example in a sheet name shown by
inspect,diff,readorvalidate);--jsonwrites control and bidirectional characters as\uXXXXescapes (the same JSON value).xlvane migratedoes not follow symbolic links, and--forcechanges theexceljsentry of the dependency section instead of the first"exceljs"in the file (which could be inoverrides). - CSV formula injection: text that starts with a control character (NUL included) or with the small forms
﹦,﹢,﹣,﹫also gets the leading', as a precaution. readTableStreamwithout a header no longer throws aRangeErroron rows with very many cells, and its output budget followslimits.maxCellswhen given.
@xlvane/compat
xlsx.loadlimits the cells it creates for merged ranges, tables and column definitions (XLV_E_LIMIT_EXCEEDED); before, one merged range covering the whole sheet ran out of memory. Checking a new merge against earlier ones takes linear time. Many sheets declaring a million rows in their dimension are refused instead of being scanned row by row.workbook.csvescapes the same additional formula-like starts astoCSV.
1.1.0
xlvane
- Sheet ids:
addSheet(name, { sheetId })and thesheetIdof a streamed sheet set the sheet's id in the file (1 to 65534, unique); other sheets get the lowest unused ids, so workbooks without given ids are written as before. Reading givessheet.sheetIdandStreamSheetInfo.sheetId(nullwithXLV_W_INVALID_VALUEfor a missing, invalid or repeated id), andinspect()/xlvane inspect --jsonreport it per sheet. - Split windows:
view({ split: { x, y, topLeftCell } })writes the top-left cell of the bottom-right pane (pane@topLeftCell), and reading gives it asview.split.topLeftCell. insertRows/deleteRowsmove the conditional formats and data validations of the [MS-XLSX] extension (extended data bars, the icon sets3Stars,3Triangles,5Boxes,NoIcons, rules written by Excel) instead of refusing the sheet, with the same results as LibreOffice. Sparklines, slicers and other extended content that refers to cells are still refused.- Fixes:
insertRows/deleteRowsnow move conditional format thresholds that refer to cells ({ type: 'formula', value: '$C$12' }); before, they kept the old reference.insertRows/deleteRowswrote a moved value containing$followed by a digit wrongly, for example a hyperlink locationMain!$A$12becameMain!$A location=4.- A sheet named like a word in the extension namespaces (for example
Main) no longer makesinsertRows/deleteRowsrefuse because of conditional formats on other sheets.
- Command line: tables, cut cells and wrapped text count terminal columns, so CJK text and emoji stay aligned; the
xlvanecommand no longer makes Node.js print its own warning when bothNO_COLORandFORCE_COLORare set (started throughnpx, npm itself may still print it).
@xlvane/compat
worksheet.idis written assheetIdand kept when a file is loaded and by themodelsetter, as in exceljs, sogetWorksheet(id)finds the same sheet after removing one, writing and loading.- A split view's
topLeftCellis written and read back, as in exceljs.
1.0.1
xlvane
xlvane migrateno longer listsaddImage({ filename })as not supported: @xlvane/compat reads the file when the workbook is written, as exceljs does. It still listsModelContainerand deep imports ofexceljs/lib/....- README: package size measured for 1.0.0, benchmark link that works outside the repository, Agent Skill install command, Deno and bundler imports, links to the changelog, issues and security policy.
- Published from GitHub Actions with npm provenance (trusted publishing); 1.0.0 was published without it.
@xlvane/compat
- README: installing (npm alias or
xlvane migrate), requirements and runtimes, TypeScript settings, the differences from exceljs most likely to matter, links. - docs/exceljs-compat.md lists
ModelContaineras not supported (constructing it throwsXLV_E_NOT_SUPPORTED, as in 1.0.0).
1.0.0
First release of xlvane and @xlvane/compat.
xlvane
- Reading XLSX, XLSM, XLTX and XLTM files from untrusted sources:
- ZIP and XML limits; no DTDs or external entities; macros are never run and links are never followed;
- every error has an
XLV_E_*code, location and hint (docs/errors.md); - damaged rows and cell references are skipped with a warning, as LibreOffice does.
inspect(): sheets, used ranges, header rows, column types and samples, merges, formulas, rich-text cells, column styles, document properties, defined names, warnings (docs/inspect-json.md).- Rich text (
{ richText: [...] },cell.richText), document properties (docProps/core.xml,workbook.properties), defined names (defineName,workbook.definedNames), column default styles and built-in number format ids (such as14), read and written. - Hyperlinks (external and in-workbook, written per ECMA-376), notes (comments, with rich text and author), tab colour, sheet view (zoom, grid lines, split) and extended document properties (
docProps/app.xml: company, manager), read and written, also by the streaming writer. - Pictures (PNG, JPEG, GIF):
addImagewith range, corner or size anchors and a sheet background; reading givessheet.imageswith anchors and image bytes;insertRows/deleteRowsmove them. - Tables (
addTable,sheet.tables,readTable(bytes, { table })): header, totals row withSUBTOTALfunctions, calculated columns and the 60 built-in table styles, read and written, also by the streaming writer;insertRows/deleteRowsmove them. - Writing with styles (fonts with every ECMA-376 property, pattern and gradient fills, borders including diagonals, alignment, number formats, cell protection), column widths, row heights, outline levels, merges, frozen and split panes, autofilter, hidden sheets, workbook views and full recalculation on load; deterministic output. Style values and counts are checked against the limits Office documents in [MS-OI29500]. Cells that have only a style are kept on read (
sheet.styledCells()). - Formulas: plain, array and shared formulas read and written.
- Sheet rules: data validation and conditional formatting (including Excel 2010 data bars and icon sets), sheet and workbook protection with passwords ([MS-OFFCRYPTO] §2.4.2.4;
hashPassword,verifyPassword), page setup, headers and footers, page breaks, print area and print titles. - Task API:
readTablewith Standard Schema validation,writeTable;toCSV/fromCSVwith CSV-injection escaping,toJSON/fromJSON;editCells/appendRows, which keep everything else in the file unchanged;insertRows/deleteRows, which move formulas, merged cells, links, notes, conditional formats, data validation and defined names with the rows (xlvane edit --insert-rows/--delete-rows);adjustFormula/adjustRangefor formula text;diff.
- Streaming:
openWorkbookStream,writeWorkbookStream,readTableStream,writeTableStream. - Node.js helpers in
xlvane/node. - The
xlvanecommand line:inspect,read,convert,create,edit,diff,validate,migrate;--jsonwith documented schemas (docs/cli-json.md).
- Agent Skill (
skills/xlvane/SKILL.md), the documentation andllms-full.txtare included in the package. - Tested in Node.js 22, 24 and 26, Bun, Deno, Chromium and Cloudflare Workers (workerd), and on 340 files of the Apache POI test corpus.
@xlvane/compat
- The exceljs 4.4.0 API on xlvane, for switching with
"exceljs": "npm:@xlvane/compat@^1": workbooks, worksheets, rows, columns, cells, styles, rich text, hyperlinks, notes, formulas (incl. shared and array formulas andfillFormula), merges, defined names, data validation, conditional formatting, protection, page setup, tables, images, row and column operations,workbook.csv, streamingWorkbookWriter/WorkbookReader, and the documented deep imports. - Where exceljs writes data the specification or Excel rejects, or loses data, xlvane writes valid data and keeps it; every difference is listed in docs/exceljs-compat.md. Row and column operations move formulas, merges, notes and names as a spreadsheet application does. CSV output escapes formula-like text by default (
formulaInjection: 'off'gives exceljs's output).
Limitations
- Formulas are not calculated: xlvane reads and writes formula text and the cached results stored in the file. Edited files ask spreadsheet applications to recalculate when they are opened.
- Legacy
.xlsfiles and password-encrypted workbooks are not read (XLV_E_UNSUPPORTED_CONTAINER). Sheet and workbook protection passwords, which are not encryption, are supported. - Charts, shapes, pivot tables, slicers and form controls are not modelled: reading skips them (drawings with a warning),
editCellskeeps them unchanged, andinsertRows/deleteRowsrefuse sheets where they would have to move. insertRows/deleteRowsalso refuse sheets whose conditional formats use the [MS-XLSX] extension, which xlvane writes for data bars with an extension setting (gradient,borderColor,negativeFillColor,negativeBorderColor,axisPosition,axisColor,direction, or anautoMin/autoMaxthreshold) and for the icon sets3Stars,3Triangles,5BoxesandNoIcons; insert the rows before adding such rules, or add the rules again after the change.readTableStreamfixes its columns from the first rows it reads;readTableuses the whole sheet.- JSON has no date type:
fromJSONkeeps ISO date strings as text (fromCSVrecognises them). - The command line reads files only, not standard input.
Source: CHANGELOG.md (version 1.2.2)