Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[nodejs] Merge PDFs using pdf-lib

https://github.com/Hopding/pdf-lib

const { PDFDocument } = require('pdf-lib')

// files = [{ fileName: 'test1.pdf, content: arraybuffer },{ fileName: 'test2.pdf, content: arraybuffer }]

mergePdfs: async function (files) {
        try {
            const mergedPdf = await PDFDocument.create()

            for (let file of files) {
                const pdf = await PDFDocument.load(file.content)
                const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
                copiedPages.forEach((page) => mergedPdf.addPage(page))
            }

            const mergedPdfFile = await mergedPdf.save()
            const buffer = Buffer.from(mergedPdfFile)
            return await buffer.toString('base64') // return as buffer or base64 encoded file
        } catch (err) {
            console.error(err.message)
        }
}

[PDF.js] Get PDF Viewer when it’s available in DOM and fully initialized

https://github.com/mozilla/pdf.js/wiki/Third-party-viewer-usage

<iframe id="pdf-js-viewer" src="/pdf/web/viewer.html?file=" title="webviewer" frameborder="0" width="100%" height="700" allowfullscreen="" webkitallowfullscreen=""/>
            displayPdf: async function (id) { 
                const pdfArrayBuffer= await getPdf(id)
                const pdfViewerIFrame = await getPdfViewer()
                await pdfViewerIFrame.contentWindow.PDFViewerApplication.initializedPromise
                await pdfViewerIFrame.contentWindow.PDFViewerApplication.open(pdfArrayBuffer)
            },

            getPdfViewer: function (id = 'pdf-js-viewer') {
                return new Promise((resolve, reject) => {
                    let pdfViewerIFrame = document.getElementById(id)
                    //if already loaded in DOM, return it
                    if (pdfViewerIFrame?.contentWindow?.PDFViewerApplication) {
                        resolve(pdfViewerIFrame)
                    } else {
                        //if not loaded yet, set up eventListener
                        document.addEventListener("webviewerloaded", async () => {
                            pdfViewerIFrame = document.getElementById(id)
                            resolve(pdfViewerIFrame)
                        })
                    }
                })
            }

This logic helped me to get the PDFViewerApplication in every situation correctly, for example when reloading the page with F5 or when having the PDF viewer already loaded and just wanting to open another PDF file.

[nodejs] workspaces

If you have subdirectories or additional applications which have its own package.json file, you can add them via the workspaces setting to your main project.

 {
  "name": "my-project",
  "workspaces": [ 
     "./app/*"
   ]
}

When running npm install it will now also install the dependencies of all projects in the app folder.

[JavaScript] Clone an object containing a file as ArrayBuffer

Use the build in function structuredClone() to copy all kind of complex JS types.

Official documentation: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types

Comparison to other copy techniques like spread or json.stringify: https://www.builder.io/blog/structured-clone

[nodejs] Node Version Manager (NVM)

# Install script: https://github.com/nvm-sh/nvm#install--update-script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash

# check current used node version
node -v

# list local available node versions
nvm list

# list all released node versions
nvm ls-remote

# install specific node version and switch to it
nvm install v20.5.1

# switch to a specific node version, which is already installed
nvm use v20.5.1

[nodejs] Create buffer from stream

Using a promise

const stream2Buffer = async () => {
        return new Promise(function (resolve, reject) {
                const chunks = []
                stream.on('data', chunk => chunks.push(chunk))
                stream.on('end', () => resolve(Buffer.concat(chunks)))
                stream.on("error", err => reject(err))
        })
}
const buffer = await stream2Buffer()

A stream is also iterable (see here), so you can also use for await...of (example)

        const chunks = []
        for await (const chunk of stream) {
            chunks.push(chunk)
        }
        const buffer = Buffer.concat(chunks)