Problem regarding Express REST API on server side (nodeJS): window is not defined

Hi there,
I’ve been facing an issue regarding the merge functionality from the Express REST API Utility package (installed through npm) on my server (running in a node js environment):
In the documentation, it is said that we can run this utility client side or server side

It can be used on either the server or the client. (Quotation from the rest api utility documentation page)

, but there is no documentation on how to set it up on a server, so I supposed that the configuration was the same on both sides.

I imported the library using:

const ExpressUtils = require('@pdftron/pdfjs-express-utils').default;
const utils = new ExpressUtils({
  serverKey: 'my_server_key',
  clientKey: 'my_client_key'

Nonetheless, when I launch my server, error instantly happens, saying that window is not defined.
After looking at the package, I can see that normally the library check for isClient || isServer but it doesn’t seem like it’s working.
What can I do ? is there anything wrong with how I instantiated this package ?

NB: I also tried to call directly the endpoint using isomorphic fetch library as you do in the express rest api package, I used ‘cross-blob’ and a nodejs package called ‘atob’ library in order to generate a blob like object from a buffer encoded as a base64 string that I get from doing a fs.readFileSync(file_path)
Here is my code:

/* eslint-disable no-async-promise-executor */
const Blob = require('cross-blob');
const atob = require('atob');
const fetch = require('cross-fetch').default;
const FormData = require('form-data');

const utils_api_merge = async (file, xfdf) => {

  const formData = new FormData();
  formData.append('file', file);
  formData.append('xfdf', xfdf);
  formData.append('license', 'my_server_key');
  try {
    const fetch_resp = await fetch('', {
      method: 'post',
      body: formData,
      headers: JSON.stringify(formData.getHeaders())

    if (fetch_resp.status >= 400) {
      throw new Error('Bad response from server on merging file');

    const response = await fetch_resp.json();

    const { url, key, id } = response;
    console.log(response, 'RESP');

    const mergedFileBlob = await fetch(url, {
      headers: {
        Authorization: key

    if (mergedFileBlob.status >= 400) {
      throw new Error('Bad response from server on getting file');

    return  await mergedFileBlob.blob();
  } catch (e) {
    return e;

const merge_edits = async (doc, base64_file) => {
  return new Promise(async (resolve, reject) => {
    try {
      const fileData = base64ToBlob(base64_file.toString('base64'));
      const xfdf = doc.xfdf_string.split('<?xml version="1.0" encoding="UTF-8" ?>')[1];
      const resp = await utils_api_merge(fileData, xfdf);
      console.log(resp.arrayBuffer(), 'FILE DATA AFTER MERGE');
    } catch (e) {
      console.log(e, 'ERROR IN MERGE EDITS');

function base64ToBlob(base64) {
  const binaryString = atob(base64);
  const len = binaryString.length;
  const bytes = new Uint8Array(len);
  for (let i = 0; i < len; ++i) {
    bytes[i] = binaryString.charCodeAt(i);

  return new Blob([bytes], { type: 'application/pdf' });

exports.merge_edits = merge_edits;

Then I get this error:

TypeError: source.on is not a function
3|pdf_corrector  |     at Function.DelayedStream.create (pdf_corrector/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
3|pdf_corrector  |     at FormData.CombinedStream.append (pdf_corrector/node_modules/combined-stream/lib/combined_stream.js:45:37)
3|pdf_corrector  |     at FormData.append (pdf_corrector/node_modules/form-data/lib/form_data.js:75:3)
3|pdf_corrector  |     at utils_api_merge (pdf_corrector/utils/mergeEditsOnDoc.js:10:12)
3|pdf_corrector  |     at pdf_corrector/utils/mergeEditsOnDoc.js:51:26
3|pdf_corrector  |     at new Promise (<anonymous>)
3|pdf_corrector  |     at merge_edits (pdf_corrector/utils/mergeEditsOnDoc.js:47:10)
3|pdf_corrector  |     at pdf_corrector/routes/medias/index.js:394:38
3|pdf_corrector  |     at Layer.handle [as handle_request] (pdf_corrector/node_modules/express/lib/router/layer.js:95:5)
3|pdf_corrector  |     at next (pdf_corrector/node_modules/express/lib/router/route.js:137:13) ERROR IN MERGE EDITS

Thank you for your time

Hi Lenny!

Thanks for the bug report,

I will look into this today and hopefully push a fix. I’ll keep you posted.



I just published 1.3.0 which should fix your issue.

Let me know if you have any more problems.


Hi there Logan, thanks for taking care of that, I don’t get window is not defined anymore, but there is another problem now:

I use this function to merge xfdf on a pdf:

const merge_xfdf = async (buffer, xfdf) => {

  const response = await api_utils.merge(); // merge XFDF

  const mergedFile = await response.getBlob();
  await response.deleteFile();

  return mergedFile;
  • The param buffer is the data that I get as a Buffer by doing fs.readFileSync(my_file_path) in another function.
  • The param xfdf is the string containing my xfdf string from where I remove the xml tag.

This is the response that I get back:

3|pdf_corrector  | Error: getBlob cannot be executed in this instance: There is no output file to fetch
3|pdf_corrector  |     at s (pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:141548)
3|pdf_corrector  |     at e.<anonymous> (pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:143523)
3|pdf_corrector  |     at pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:143122
3|pdf_corrector  |     at (pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:143227)
3|pdf_corrector  |     at pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:142163
3|pdf_corrector  |     at new Promise (<anonymous>)
3|pdf_corrector  |     at d (pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:141908)
3|pdf_corrector  |     at e.getBlob (pdf_corrector/node_modules/@pdftron/pdfjs-express-utils/dist/node/index.js:13:143417)
3|pdf_corrector  |     at merge_xfdf (pdf_corrector/utils/mergeEditsOnDoc.js:58:37)
3|pdf_corrector  |     at processTicksAndRejections (internal/process/task_queues.js:97:5)

Thanks for your time

Hi there,

We have ran into a few issues with the server-side version of our package and are doing a bit of testing/fixing. We will push a new, stable version ASAP and I will let you know when that happens.

Sorry about this!


Hey there,

I just pushed version 1.3.1 which will work in a node environment.

One thing that I had to change is that we no longer accept a buffer and instead accept a readstream.

The change is as simple as chaning fs.readFileSync to fs.createReadStream:

Here is an example:

const Utils = require('@pdftron/pdfjs-express-utils').default;
const fs = require('fs');

const u = new Utils({
  serverKey: 'YOUR_KEY_HERE'

(async () => {
  const readStream = fs.createReadStream('myPDF.pdf');

  const xfdf = `<?xml version="1.0" encoding="UTF-8" ?><xfdf xmlns="" xml:space="preserve"><pdf-info xmlns="" version="2" import-version="3" /><fields /><annots><square page="0" rect="414.95599999999996,1393.51,635.3059999999999,1546.05" color="#000000" flags="print" name="5616161f-3466-9898-dfea-228357f8c855" title="Guest" subject="Rectangle" date="D:20210713134128-07'00'" width="9.437031125299281" creationdate="D:20210713134127-07'00'"/></annots><pages><defmtx matrix="1,0,0,-1,-309.27599999999995,1630.8" /></pages></xfdf>`
  const response = await u.merge(); // merge XFDF

  const mergedFile = await response.getBlob();
  await response.deleteFile();

  fs.writeFileSync('out.pdf', mergedFile)

Thank you for your patience!

1 Like

Hi there,
thanks again Logan everything is working now, this new version cleared every problems

Have a great evening,

1 Like