Source: index.js

/**
 * WebMerge module.
 * @module webmerge
 */

'use strict'

const request = require('request')


const WEB_MERGE_BASE_URL = 'https://www.webmerge.me'
const API_ENDPOINT = '/api/documents'
const MERGE_ENDPOINT = '/merge'
const ROUTE_ENDPOINT = '/route'
const TOOLS_ENDPOINT = '/tools'

/**
 * Utility function to convert callbacks to Promise
 * @param fn - Node-style callback
 */
const promiseFromCallback = fn => new Promise((resolve, reject) => {
  fn((err, response) => {
    if (err) return reject(err)
    return resolve(response)
  })
})

/**
 * API client with a callback API
 */
class WebMergeAPI {

  /**
   * Create an API client that uses callbacks.
   * @param {string} key - API key
   * @param {string} secret - API secret
   */
  constructor(key, secret) {
    this.client = request.defaults({
      baseUrl: WEB_MERGE_BASE_URL,
      auth: {
        username: key,
        password: secret,
        sendImmediately: true,
      },
      json: true,
    })
  }

  /**
   * Retrieve a list of documents.
   * @param {Object} options
   * @param {string} options.search - Search term
   * @param {string} options.folder - Folder name
   * @param callback
   */
  getDocuments(options, callback) {
    return this.client.get({
      url: `${API_ENDPOINT}`,
      qs: options,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a specific document.
   * @param {number} id - Document ID
   * @param callback
   */
  getDocument(id, callback) {
    return this.client.get({
      url: `${API_ENDPOINT}/${id}`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a list of fields for a specific document.
   * @param {number} id - Document ID
   * @param callback
   */
  getDocumentFields(id, callback) {
    return this.client.get({
      url: `${API_ENDPOINT}/${id}/fields`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve the file that was uploaded for a specific document (pdf, docx, xlsx, or pptx)
   * @param {number} id - Document ID
   * @param callback
   */
  getDocumentFiles(id, callback) {
    return this.client.get({
      url: `${API_ENDPOINT}/${id}/file`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Create a new document.
   * Depending on the type of document you are creating, different parameters are required
   * @param {Object} data - See {@link https://www.webmerge.me/developers/documents}
   * @param callback
   */
  createDocument(data, callback) {
    return this.client.post({
      url: `${API_ENDPOINT}`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Update a document.
   * You cannot change the type of document, but you can change many of the other settings as well as change the
   * contents of the document. Only parameters that are sent in the request will be updated.
   * @param {number} id - Document ID
   * @param {Object} data
   * @param callback
   */
  updateDocument(id, data, callback) {
    return this.client.put({
      url: `${API_ENDPOINT}/${id}`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Merge a document.
   * @param {number} id - Document ID
   * @param {string} key - Document key
   * @param {Object} data - Data to be merged
   * @param {boolean} isTestMode - Merge the document in "test" mode
   * @param {boolean} downloadFile - Return the merged document in response
   * @param callback
   */
  mergeDocument(id, key, data, isTestMode, downloadFile, callback) {
    return this.client.post({
      url: `${MERGE_ENDPOINT}/${id}/${key}`,
      qs: {
        test: isTestMode ? 1 : 0,
        download: downloadFile ? 1 : 0,
      },
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Create a copy of a document.
   * @param {number} id - Document ID
   * @param {Object} data
   * @param {string} data.name - Name of the new document
   * @param callback
   */
  copyDocument(id, data, callback) {
    return this.client.post({
      url: `${API_ENDPOINT}/${id}/copy`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Delete a document
   * @param {number} id - Document ID
   * @param callback
   */
  deleteDocument(id, callback) {
    return this.client.delete({
      url: `${API_ENDPOINT}/${id}`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a list of data routes.
   * @param callback
   */
  getDataRoutes(callback) {
    return this.client.get({
      url: `${ROUTE_ENDPOINT}`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a specific data route
   * @param {number} id - Data Route ID
   * @param callback
   */
  getDataRoute(id, callback) {
    return this.client.get({
      url: `${ROUTE_ENDPOINT}/${id}`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a list of fields for a specific data route.
   * This includes fields from all documents in routing rules.
   * @param {number} id - Data Route ID
   * @param callback
   */
  getDataRouteFields(id, callback) {
    return this.client.get({
      url: `${ROUTE_ENDPOINT}/${id}/fields`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Retrieve a list of rules for a specific data route.
   * @param {number} id - Data Route ID
   * @param callback
   */
  getDataRouteRules(id, callback) {
    return this.client.get({
      url: `${ROUTE_ENDPOINT}/${id}/rules`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Merge a data route.
   * @param {number} id - Document ID
   * @param {string} key - Document key
   * @param {Object} data - Data to be merged
   * @param {boolean} isTestMode - Merge the document in "test" mode
   * @param {boolean} downloadFile - Return the merged document in response
   * @param callback
   */
  mergeDataRoute(id, key, data, isTestMode, downloadFile, callback) {
    return this.client.post({
      url: `${ROUTE_ENDPOINT}/${id}/${key}`,
      qs: {
        test: isTestMode ? 1 : 0,
        download: downloadFile ? 1 : 0,
      },
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Create a new data route.
   * @param {Object} data - https://www.webmerge.me/developers/routes
   * @param callback
   */
  createDataRoute(data, callback) {
    return this.client.post({
      url: `${ROUTE_ENDPOINT}`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Update a data route.
   * @param {number} id - Data Route ID
   * @param {Object} data
   * @param callback
   */
  updateDataRoute(id, data, callback) {
    return this.client.put({
      url: `${ROUTE_ENDPOINT}/${id}`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Delete a data route.
   * @param {number} id - Data Route ID
   * @param callback
   */
  deleteDataRoute(id, callback) {
    return this.client.delete({
      url: `${ROUTE_ENDPOINT}/${id}`,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Combine multiple files (pages) into a single file.
   * @param {Object} data - See {@link https://www.webmerge.me/developers/tools}
   * @param callback
   */
  combineFiles(data, callback) {
    return this.client.post({
      url: `${TOOLS_ENDPOINT}/combine`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }

  /**
   * Convert file to PDF
   * @param {Object} data
   * @param {Object} data.file
   * @param {string} data.file.name - File Name
   * @param {string} data.file.url - Remote File URL (required if 'contents' is empty)
   * @param {string} data.file.contents - Base64-encoded file (required if 'url' is empty)
   * @param callback
   */
  convertToPDF(data, callback) {
    return this.client.post({
      url: `${TOOLS_ENDPOINT}/convert_to_pdf`,
      body: data,
    }, (err, response, body) => {
      if (err) return callback(err)
      return callback(null, body)
    })
  }
}


/**
 * API client with a promise API
 * @extends WebMergeAPI
 */
class WebMergePromiseAPI extends WebMergeAPI {

  /**
   * Create an API client that uses Promises.
   * @param {string} key - API key
   * @param {string} secret - API secret
   */
  constructor(key, secret) {
    super(key, secret)
  }

  /**
   * Retrieve a list of documents.
   * @param {Object} options
   * @param {string} options.search - Search term
   * @param {string} options.folder - Folder name
   */
  getDocuments(options) {
    return promiseFromCallback(cb => super.getDocuments(options, cb))
  }

  /**
   * Retrieve a specific document.
   * @param {number} id - Document ID
   */
  getDocument(id) {
    return promiseFromCallback(cb => super.getDocument(id, cb))
  }

  /**
   * Retrieve a list of fields for a specific document.
   * @param id - Document ID
   */
  getDocumentFields(id) {
    return promiseFromCallback(cb => super.getDocumentFields(id, cb))
  }

  /**
   * Retrieve the file that was uploaded for a specific document (pdf, docx, xlsx, or pptx)
   * @param id - Document ID
   */
  getDocumentFiles(id) {
    return promiseFromCallback(cb => super.getDocumentFiles(id, cb))
  }

  /**
   * Create a new document.
   * Depending on the type of document you are creating, different parameters are required
   * @param {Object} data - See {@link https://www.webmerge.me/developers/documents}
   */
  createDocument(data) {
    return promiseFromCallback(cb => super.createDocument(data, cb))
  }

  /**
   * Update a document.
   * You cannot change the type of document, but you can change many of the other settings as well as change the
   * contents of the document. Only parameters that are sent in the request will be updated.
   * @param {number} id - Document ID
   * @param data
   */
  updateDocument(id, data) {
    return promiseFromCallback(cb => super.updateDocument(id, data, cb))
  }

  /**
   * Merge a data route.
   * @param {number} id - Document ID
   * @param {string} key - Document key
   * @param {Object} data - Data to be merged
   * @param {boolean} isTestMode - Merge the document in "test" mode
   * @param {boolean} downloadFile - Return the merged document in response
   */
  mergeDocument(id, key, data, isTestMode, downloadFile) {
    return promiseFromCallback(cb => super.mergeDocument(id, key, data, isTestMode, downloadFile, cb))
  }

  /**
   * Create a copy of a document.
   * @param {number} id - Document ID
   * @param {Object} data
   * @param {string} data.name - Name of the new document
   */
  copyDocument(id, data) {
    return promiseFromCallback(cb => super.copyDocument(id, data, cb))
  }

  /**
   * Delete a document
   * @param {number} id - Document ID
   */
  deleteDocument(id) {
    return promiseFromCallback(cb => super.deleteDocument(id, cb))
  }

  /**
   * Retrieve a list of data routes.
   * @param callback
   */
  getDataRoutes(callback) {
    return promiseFromCallback(cb => super.getDataRoutes(callback, cb))
  }

  /**
   * Retrieve a specific data route
   * @param {number} id - Data Route ID
   */
  getDataRoute(id) {
    return promiseFromCallback(cb => super.getDataRoute(id, cb))
  }

  /**
   * Retrieve a list of fields for a specific data route.
   * This includes fields from all documents in routing rules.
   * @param {number} id - Data Route ID
   */
  getDataRouteFields(id) {
    return promiseFromCallback(cb => super.getDataRouteFields(id, cb))
  }

  /**
   * Retrieve a list of rules for a specific data route.
   * @param {number} id - Data Route ID
   */
  getDataRouteRules(id) {
    return promiseFromCallback(cb => super.getDataRouteRules(id, cb))
  }

  /**
   * Merge a data route.
   * @param {number} id - Document ID
   * @param {string} key - Document key
   * @param {Object} data - Data to be merged
   * @param {boolean} isTestMode - Merge the document in "test" mode
   * @param {boolean} downloadFile - Return the merged document in response
   */
  mergeDataRoute(id, key, data, isTestMode, downloadFile) {
    return promiseFromCallback(cb => super.mergeDataRoute(id, key, data, isTestMode, downloadFile, cb))
  }

  /**
   * Create a new data route.
   * @param {Object} data - https://www.webmerge.me/developers/routes
   */
  createDataRoute(data) {
    return promiseFromCallback(cb => super.createDataRoute(data, cb))
  }

  /**
   * Update a data route.
   * @param {number} id - Data Route ID
   * @param {Object} data
   */
  updateDataRoute(id, data) {
    return promiseFromCallback(cb => super.updateDataRoute(id, data, cb))
  }

  /**
   * Delete a data route.
   * @param {number} id - Data Route ID
   */
  deleteDataRoute(id) {
    return promiseFromCallback(cb => super.deleteDataRoute(id, cb))
  }

  /**
   * Combine multiple files (pages) into a single file.
   * @param {Object} data - See {@link https://www.webmerge.me/developers/tools}
   */
  combineFiles(data) {
    return promiseFromCallback(cb => super.combineFiles(data, cb))
  }

  /**
   * Convert file to PDF
   * @param {Object} data
   * @param {Object} data.file
   * @param {string} data.file.name - File Name
   * @param {string} data.file.url - Remote File URL (required if 'contents' is empty)
   * @param {string} data.file.contents - Base64-encoded file (required if 'url' is empty)
   */
  convertToPDF(data) {
    return promiseFromCallback(cb => super.convertToPDF(data, cb))
  }
}

/**
 * API client with a callback API
 */
module.exports.WebMergeAPI = WebMergeAPI
/**
 * API client with a promise API
 */
module.exports.WebMergePromiseAPI = WebMergePromiseAPI