npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@concordance-wiki/plugin-convert-libreoffice

v1.0.0

Published

Converts docx, pptx and xlsx documents to PDF through headless LibreOffice, with a fingerprint cache.

Readme


Why

A document the wiki can only offer for download is a document nobody opens. This plugin turns the .docx, .pptx and .xlsx files of your repositories into PDF through headless LibreOffice, so that the site previews them without the original application, and extracts the text of every page with pdf.js, for .pdf sources too. That text is what lets the build recognise the words of your business inside a slide deck and cite the page where they appear. It is carried by @concordance-wiki/concordance and by the container image, LibreOffice included; install it on its own next to @concordance-wiki/cli, with LibreOffice on the machine that builds.

Quick start

npm install --save-dev @concordance-wiki/plugin-convert-libreoffice

Then declare it in concordance.yaml, and make sure soffice --version answers on the build machine:

plugins:
  - "@concordance-wiki/plugin-convert-libreoffice"

Every office document and PDF of a source gets a PDF representation and the text of its pages, cached by fingerprint; the conversion block bounds the work:

conversion:
  timeout_s: 120
  max_size_mb: 50
  cache: .concordance-cache

A source that must stay downloadable without a preview declares convert: false.

What you get

  • A preview in the page: the PDF of every document opened in the site's viewer, page by page, with a find box over the extracted text.
  • Every page searchable: the text of each page goes through the same recognition as a note, so a term cites the page of a deck the way it cites the line of a note.
  • Converted once: the cache key is the SHA-256 of the source bytes; an unchanged document is never reconverted nor re-read, whatever its path.
  • Bounded work: conversion.timeout_s and conversion.max_size_mb cap each conversion; a failure is a W-CONV-FAILED finding and the document stays downloadable.
  • Suspect output named: a large source whose PDF holds no text is a W-CONV-SUSPECT finding, reproduced on every build.
  • Graceful without LibreOffice: LibreOffice is an optional dependency; when soffice is missing the build says so once (W-PLUGIN-DISABLED, informational), PDF sources are still read, and every office document gets a W-CONV-FAILED naming the missing command, downloadable all the same.
  • Nothing written next to a source: conversions run in a temporary folder under the cache, with their own user profile, in parallel.

Documentation

Part of Concordance, MIT licence.

Contribution

Two converter contributions, both producing pdf and text: one for the three office extensions, one for .pdf, whose sources are kept as their own PDF representation without running LibreOffice. The manifest declares LibreOffice as a system dependency detected through soffice --version: when the command is missing, the registry disables the plugin with a W-PLUGIN-DISABLED finding and the documents stay downloadable entities, PDF sources included. Thumbnails are a later story.

Behaviour

  • The cache key is the SHA-256 of the source bytes: the PDF is written to <cache>/convert/<sha256>.pdf, the text of its pages next to it as <sha256>.text.json ({ "pages": string[] }, one entry per page), and an unchanged document is never reconverted nor re-read, whatever its path. A cache of a previous version holding the PDF alone gets its text extracted once.
  • The source is copied to a temporary folder under <cache>/convert/work/<sha256>/ and soffice --headless --norestore --convert-to pdf runs there with its own user profile (-env:UserInstallation), so that parallel instances do not block each other; the folder is removed afterwards. Nothing is written next to the source.
  • A document above maxSizeBytes is not converted; a conversion past timeoutMs is killed. Both yield a W-CONV-FAILED finding, as does a non-zero exit (the message carries the exit code and the first line of stderr) or a run that produces no PDF. The output has no representation in that case: the document remains available for download.
  • A source above 100 KiB whose PDF has no extractable text yields a W-CONV-SUSPECT finding. The finding is reproduced on cache hits so that a second build reports the same anomalies.
  • The text comes from pdfjs-dist, which declares @napi-rs/canvas as an optional dependency for drawing; the plugin never draws (it reads getTextContent alone), so the native module, installed when a binary exists for the platform and skipped otherwise, is never loaded.
  • extractPdfPages(bytes) gives the text of every page in reading order, the items of a page joined by spaces, and no page for bytes that are not a PDF; extractPdfText joins them, one line per page.
  • convertMany(inputs, parallelism, convert) runs conversions through a small pool and returns the results in input order, whatever the completion order.

Testing

Unit tests replace LibreOffice with a fake command runner. The integration test runs the installed soffice only when CONCORDANCE_INTEGRATION=1 is set, which the conversion job of the pipeline does after installing LibreOffice; it is skipped otherwise, it fails when the opt-in finds no command, and every line is covered without it.