diff --git a/.swagger-codegen-ignore b/.swagger-codegen-ignore index c57eb1ac..66288b4a 100644 --- a/.swagger-codegen-ignore +++ b/.swagger-codegen-ignore @@ -25,7 +25,6 @@ .swagger-codegen-ignore .gitignore CHANGELOG.md -README.md git_push.sh # Project files @@ -39,4 +38,4 @@ test/*/*.spec.js test/assert-equals.js src/OAuth.js src/RestApi.js -src/oauth/ \ No newline at end of file +src/oauth/ diff --git a/CHANGELOG.md b/CHANGELOG.md index b3bf5465..a25d30c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ See [DocuSign Support Center](https://support.docusign.com/en/releasenotes/) for Product Release Notes. +## [v7.0.2] - eSignature API v2.1-24.1.01.00 - 2024-06-06 +### Changed +- Resolved an issue with the PDF download logic that caused corrupted data. ## [v7.0.1] - eSignature API v2.1-24.1.01.00 - 2024-05-24 ## Resolved "Generate Access Token SDK Method is broken since most recent RC Version" ## [v7.0.0] - eSignature API v2.1-24.1.01.00 - 2024-05-22 diff --git a/README.md b/README.md index e6b11a22..01b12513 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,101 @@ -# The Official DocuSign eSignature Node Client SDK +# The Official Docusign eSignature Node Client SDK [![NPM version][npm-image]][npm-url] [![NPM downloads][downloads-image]][downloads-url] -[![Build status][travis-image]][travis-url] -[![Coverage Status][coveralls-image]][coveralls-url] -[NPM module](https://www.npmjs.com/package/docusign-esign) that wraps the DocuSign API - -[Documentation about the DocuSign API](https://developers.docusign.com/) +The Docusign SDK makes integrating Docusign into your apps and websites a seamless experience. + +## Table of Contents +- [Introduction](#introduction) +- [Installation](#installation) + * [Version Information](#versionInformation) + * [Requirements](#requirements) + * [Compatibility](#compatibility) + * [NPM](#npm) +- [Dependencies](#dependencies) +- [API Reference](#apiReference) +- [Code Examples](#codeExamples) +- [OAuth Implementations](#oauthImplementations) +- [Changelog](#changeLog) +- [Support](#support) +- [License](#license) +- [Additional Resources](#additionalResources) + + +## Introduction +Integrate eSignatures into your application in minutes. The secure and award-winning Docusign eSignature API makes requesting signatures, automating forms, and tracking documents directly from your app easy. + + +## Installation +This client SDK is provided as open source, which enables you to customize its functionality to suit your particular use case. To do so, download or clone the repository. If the SDK’s given functionality meets your integration needs, or if you’re working through our [code examples](https://developers.docusign.com/docs/esign-rest-api/how-to/) from the [Docusign Developer Center](https://developers.docusign.com/), you merely need to install it by following the instructions below. -[Documentation about this package](http://docusign.github.io/docusign-esign-node-client) - + +### Version Information +- **API version**: v2.1 +- **Latest SDK version**: 7.0.2 + ## Requirements * Node 12 -* Free [developer account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16531) +* Free [developer account](https://go.docusign.com/o/sandbox/?postActivateUrl=https://developers.docusign.com/) + ## Compatibility * Node 12+ -## Installation -This SDK is provided as open source, which enables you to customize its functionality to suit your particular use case. To do so, download or clone the repository. If the SDK’s given functionality meets your integration needs, or if you’re working through our [code examples](https://developers.docusign.com/docs/esign-rest-api/how-to/) from the [DocuSign Developer Center](https://developers.docusign.com/), you merely need to install it by following the instructions below. - + ### NPM: 1. Open your preferred command-line console, then navigate to your project. 2. In the console, type the following commands: \ npm install docusign-esign -save -## Dependencies + +## SDK Dependencies This client has the following external dependencies: **Minimum:** -* DocuSign-eSign -* axios 1.6.8 - -**Optional:** -* Async v2.6.2 -* Jsonwebtoken v9.0.0 -* Passport-oauth2 -* Path - +* docusign-esign +* Axios v1.6.8+ +* @devhigley/parse-proxy v1.0.3+ +* Csv-stringify v1.0.0+ +* Jsonwebtoken v9.0.0+ +* Passport-oauth2 v1.6.1+ +* Safe-buffer v5.1.2+ + + +## API Reference +You can refer to the API reference [here](https://developers.docusign.com/docs/esign-rest-api/reference/). + + ## Code examples +Explore our GitHub repository for the [Launcher](https://github.com/docusign/code-examples-node/), a self-executing package housing code examples for the eSignature Node SDK. This package showcases several common use cases and their respective source files. Additionally, you can download a version preconfigured for your Docusign developer account from [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/). These examples support both the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) and [JSON Web Token (JWT)](https://developers.docusign.com/platform/auth/jwt/) authentication workflows. -You can find on our GitHub a self-executing package of code examples for the eSignature C# SDK, called a [Launcher](https://github.com/docusign/code-examples-node/blob/master/README.md), that demonstrates common use cases. You can also download a version preconfigured for your DocuSign developer account from [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/). These examples can use either the [Authorization Code Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant) or [JSON Web Token (JWT)](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken) authentication workflows. - + ## OAuth implementations -For details regarding which type of OAuth grant will work best for your DocuSign integration, see [Choose OAuth Type](https://developers.docusign.com/platform/auth/choose/) in the [DocuSign Developer Center](https://developers.docusign.com/). +For details regarding which type of OAuth grant will work best for your Docusign integration, see [Choose OAuth Type](https://developers.docusign.com/platform/auth/choose/) in the [Docusign Developer Center](https://developers.docusign.com/). + +For security purposes, Docusign recommends using the [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) flow. -For security purposes, DocuSign recommends using the [Authorization Code Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant) flow. + +## Changelog +You can refer to the complete changelog [here](https://github.com/docusign/docusign-esign-node-client/blob/master/CHANGELOG.md). + ## Support -Log issues against this client through GitHub. We also have an [active developer community on Stack Overflow](http://stackoverflow.com/questions/tagged/docusignapi). +Log issues against this client SDK through GitHub. You can also reach out to us through [Docusign Community](https://community.docusign.com/developer-59) and [Stack Overflow](https://stackoverflow.com/questions/tagged/docusignapi). + ## License -The DocuSign eSignature Node Client SDK is licensed under the [MIT License](https://github.com/docusign/docusign-node-client/blob/master/LICENSE). +The Docusign eSignature Node Client SDK is licensed under the [MIT License](https://github.com/docusign/docusign-esign-node-client/blob/master/LICENSE). + ### Additional resources -* [DocuSign Developer Center](https://developers.docusign.com/) -* [DocuSign API on Twitter](https://twitter.com/docusignapi) -* [DocuSign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) -* [DocuSign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) +* [Docusign Developer Center](https://developers.docusign.com/) +* [Docusign API on Twitter](https://twitter.com/docusignapi) +* [Docusign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) +* [Docusign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) [npm-image]: https://img.shields.io/npm/v/docusign-esign.svg?style=flat [npm-url]: https://npmjs.org/package/docusign-esign [downloads-image]: https://img.shields.io/npm/dm/docusign-esign.svg?style=flat -[downloads-url]: https://npmjs.org/package/docusign-esign -[travis-image]: https://travis-ci.com/docusign/docusign-esign-node-client.svg?branch=master -[travis-url]: https://travis-ci.com/docusign/docusign-esign-node-client -[coveralls-image]: https://coveralls.io/repos/github/docusign/DocuSign-Node-Client/badge.svg?branch=master -[coveralls-url]: https://coveralls.io/github/docusign/DocuSign-Node-Client?branch=master +[downloads-url]: https://npmjs.org/package/docusign-esign \ No newline at end of file diff --git a/package.json b/package.json index 362021ad..7718be32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docusign-esign", - "version": "7.0.1", + "version": "7.0.2", "description": "DocuSign Node.js API client.", "license": "MIT", "main": "src/index.js", @@ -64,6 +64,7 @@ "jsdoc": "3.6.10", "mocha": "~5.0.4", "mocha-junit-reporter": "^1.18.0", + "pdf2json": "^3.1.3", "semistandard": "^12.0.1" } } diff --git a/src/ApiClient.js b/src/ApiClient.js index 16855aee..876e25f9 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -37,7 +37,7 @@ var defaultHeaders = { "X-DocuSign-SDK": "Node", "Node-Ver": process.version, - "User-Agent": `Swagger-Codegen/v2.1/7.0.1/node/${process.version}`, + "User-Agent": `Swagger-Codegen/v2.1/7.0.2/node/${process.version}`, }; var SCOPE_SIGNATURE = "signature"; @@ -695,13 +695,13 @@ request .then((response) => { try { - let streamData; + const streamData = []; if (requestConfig.headers["Accept"] === "application/pdf") { - response.data.on("data", (chunks) => { - streamData += chunks; + response.data.on("data", (chunk) => { + streamData.push(chunk); }); response.data.on("end", () => { - resolve(streamData); + resolve(Buffer.concat(streamData)); }); } else { data = _this.deserialize(response, returnType); @@ -719,13 +719,13 @@ request .then((response) => { try { - let streamData; + const streamData = []; if (requestConfig.headers["Accept"] === "application/pdf") { - response.data.on("data", (chunks) => { - streamData += chunks; + response.data.on("data", (chunk) => { + streamData.push(chunk); }); response.data.on("end", () => { - callback(null, streamData, response); + callback(null, Buffer.concat(streamData), response); }); } else { data = _this.deserialize(response, returnType); diff --git a/test/SdkUnitTests.js b/test/SdkUnitTests.js index 2f569f57..0d5b26a0 100644 --- a/test/SdkUnitTests.js +++ b/test/SdkUnitTests.js @@ -13,6 +13,7 @@ var axios = require('axios'); var Buffer = global.Buffer.from ? global.Buffer : require('safe-buffer').Buffer; var fs = require('fs'); +const { ValidatePdf } = require('./helpers'); var userName = config.email; var privateKey = config.privateKey; @@ -25,7 +26,6 @@ var basePath = restApi.BasePath.DEMO; var oAuthBasePath = oAuth.BasePath.DEMO; var SignTest1File = 'docs/SignTest1.pdf'; -var LargeTestDocument1 = 'docs/LargeTestDocument1.pdf'; var brandLogoPath = 'img/docusign-lgo.png'; var brandXmlPath = 'docs/brand.xml'; var accountId = ''; @@ -267,11 +267,11 @@ describe('SDK Unit Tests:', function (done) { var authUri = apiClient.getAuthorizationUri(integratorKeyAuthCode, scopes, RedirectURI, responseType, randomState); axios.get(authUri) - .then(function (res) { + .then(function (res) { assert.equal(res.status, 200); done(); }) - .catch((err)=>{ + .catch((err) => { assert.notEqual(err, undefined); }); }); @@ -670,7 +670,7 @@ describe('SDK Unit Tests:', function (done) { try { var fs = require('fs'); // read file from a local directory - fileBytes = fs.readFileSync(path.resolve(__dirname, LargeTestDocument1)); + fileBytes = fs.readFileSync(path.resolve(__dirname, SignTest1File)); } catch (ex) { // handle error console.log('Exception: ' + ex); @@ -743,6 +743,13 @@ describe('SDK Unit Tests:', function (done) { var tempFile = path.resolve(__dirname, filename); fs.writeFile(tempFile, Buffer.from(pdfBytes, 'binary'), function (err) { if (err) console.log('Error: ' + err); + ValidatePdf(tempFile).then(() => { + done(); + }).catch((error) => { + if (error) { + return done(error); + } + }); }); console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); } catch (ex) { @@ -755,7 +762,6 @@ describe('SDK Unit Tests:', function (done) { return done(error); } }); - done(); } }) .catch(function (error) { @@ -941,33 +947,36 @@ describe('SDK Unit Tests:', function (done) { var tempFile = path.resolve(__dirname, filename); fs.writeFile(tempFile, Buffer.from(pdfBytes, 'binary'), function (err) { if (err) console.log('Error: ' + err); - }); - console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); - } catch (ex) { - console.log('Exception: ' + ex); - } - diagApi.listRequestLogs() - .then(function (logsList) { - if (logsList) { - var requestLogId = logsList.apiRequestLogs[0].requestLogId; - console.log(requestLogId); - diagApi.getRequestLog(requestLogId) - .then(function (diagBytes) { - if (diagBytes) { - try { - var fs = require('fs'); - // download the document pdf - var filename = requestLogId + '.txt'; - var tempFile = path.resolve(__dirname, filename); - fs.writeFile(tempFile, diagBytes, function (err) { - if (err) console.log('Error: ' + err); + ValidatePdf(tempFile).then(() => { + diagApi.listRequestLogs() + .then(function (logsList) { + if (logsList) { + var requestLogId = logsList.apiRequestLogs[0].requestLogId; + console.log(requestLogId); + diagApi.getRequestLog(requestLogId) + .then(function (diagBytes) { + if (diagBytes) { + try { + var fs = require('fs'); + // download the document pdf + var filename = requestLogId + '.txt'; + var tempFile = path.resolve(__dirname, filename); + fs.writeFile(tempFile, diagBytes, function (err) { + if (err) console.log('Error: ' + err); + }); + console.log('Diagnostics ID ' + requestLogId + ' data has been downloaded to ' + tempFile); + done(); + } catch (ex) { + console.log('Exception: ' + ex); + done(ex); + } + } + }) + .catch(function (error) { + if (error) { + return done(error); + } }); - console.log('Diagnostics ID ' + requestLogId + ' data has been downloaded to ' + tempFile); - done(); - } catch (ex) { - console.log('Exception: ' + ex); - done(ex); - } } }) .catch(function (error) { @@ -975,13 +984,16 @@ describe('SDK Unit Tests:', function (done) { return done(error); } }); - } - }) - .catch(function (error) { - if (error) { - return done(error); - } + }).catch(function (error) { + if (error) { + return done(error); + } + }); }); + console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); + } catch (ex) { + console.log('Exception: ' + ex); + } } }) .catch(function (error) { diff --git a/test/SdkUnitTestsWithCallback.js b/test/SdkUnitTestsWithCallback.js index b1232dd4..399d5ccc 100644 --- a/test/SdkUnitTestsWithCallback.js +++ b/test/SdkUnitTestsWithCallback.js @@ -5,6 +5,7 @@ var config = require('../test-config'); var assert = require('assert'); var path = require('path'); var axios = require('axios'); +const { ValidatePdf } = require('./helpers'); var userName = config.email; var integratorKey = config.integratorKey; @@ -18,7 +19,6 @@ var basePath = restApi.BasePath.DEMO; var oAuthBasePath = oAuth.BasePath.DEMO; var SignTest1File = 'docs/SignTest1.pdf'; -var LargeTestDocument1 = 'docs/LargeTestDocument1.pdf'; var accountId = ''; var envelopeId = ''; var userId = config.userId; @@ -52,7 +52,7 @@ describe('SDK Unit Tests With Callbacks:', function (done) { if (err) { return done(err); } - apiClient.setJWTToken(res.body.access_token) + apiClient.setJWTToken(res.body.access_token); apiClient.getUserInfo(res.body.access_token, function (err, userInfo) { if (err) { @@ -228,11 +228,11 @@ describe('SDK Unit Tests With Callbacks:', function (done) { var authUri = apiClient.getAuthorizationUri(integratorKeyAuthCode, scopes, RedirectURI, responseType, randomState); axios.get(authUri) - .then(function (res) { + .then(function (res) { assert.equal(res.status, 200); done(); }) - .catch((err)=>{ + .catch((err) => { assert.notEqual(err, undefined); }); }); @@ -523,7 +523,7 @@ describe('SDK Unit Tests With Callbacks:', function (done) { try { var fs = require('fs'); // read file from a local directory - fileBytes = fs.readFileSync(path.resolve(__dirname, LargeTestDocument1)); + fileBytes = fs.readFileSync(path.resolve(__dirname, SignTest1File)); } catch (ex) { // handle error console.log('Exception: ' + ex); @@ -602,6 +602,13 @@ describe('SDK Unit Tests With Callbacks:', function (done) { var tempFile = path.resolve(__dirname, filename); fs.writeFile(tempFile, Buffer.from(pdfBytes, 'binary'), function (err) { if (err) console.log('Error: ' + err); + ValidatePdf(tempFile).then(() => { + done(); + }).catch((error) => { + if (error) { + return done(error); + } + }); }); console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); } catch (ex) { @@ -609,7 +616,6 @@ describe('SDK Unit Tests With Callbacks:', function (done) { } } }); - done(); } }); }); @@ -735,42 +741,48 @@ describe('SDK Unit Tests With Callbacks:', function (done) { var tempFile = path.resolve(__dirname, filename); fs.writeFile(tempFile, Buffer.from(pdfBytes, 'binary'), function (err) { if (err) console.log('Error: ' + err); - }); - console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); - } catch (ex) { - console.log('Exception: ' + ex); - } - diagApi.listRequestLogs(null, function (error, logsList, response) { - if (error) { - return done(error); - } - - if (logsList) { - var requestLogId = logsList.apiRequestLogs[0].requestLogId; - console.log(requestLogId); - diagApi.getRequestLog(requestLogId, function (error, diagBytes, response) { - if (error) { - return done(error); - } + ValidatePdf(tempFile).then(() => { + diagApi.listRequestLogs(null, function (error, logsList, response) { + if (error) { + return done(error); + } - if (diagBytes) { - try { - var fs = require('fs'); - // download the document pdf - var filename = requestLogId + '.txt'; - var tempFile = path.resolve(__dirname, filename); - fs.writeFile(tempFile, diagBytes, function (err) { - if (err) console.log('Error: ' + err); + if (logsList) { + var requestLogId = logsList.apiRequestLogs[0].requestLogId; + console.log(requestLogId); + diagApi.getRequestLog(requestLogId, function (error, diagBytes, response) { + if (error) { + return done(error); + } + + if (diagBytes) { + try { + var fs = require('fs'); + // download the document pdf + var filename = requestLogId + '.txt'; + var tempFile = path.resolve(__dirname, filename); + fs.writeFile(tempFile, diagBytes, function (err) { + if (err) console.log('Error: ' + err); + }); + console.log('Diagnostics ID ' + requestLogId + ' data has been downloaded to ' + tempFile); + done(); + } catch (ex) { + console.log('Exception: ' + ex); + } + } }); - console.log('Diagnostics ID ' + requestLogId + ' data has been downloaded to ' + tempFile); - done(); - } catch (ex) { - console.log('Exception: ' + ex); } + }); + }).catch(error => { + if (error) { + return done(error); } }); - } - }); + }); + console.log('Document from envelope ' + envelopeSummary.envelopeId + ' has been downloaded to ' + tempFile); + } catch (ex) { + console.log('Exception: ' + ex); + } } }); } diff --git a/test/helpers.js b/test/helpers.js index 94de025d..97a01181 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -2,6 +2,7 @@ var path = require('path'); var fs = require('fs'); var constants = require('./constants'); +const PdfParser = require('pdf2json'); var INTEGRATOR_KEY = constants.INTEGRATOR_KEY; var OAUTH_BASE_PATH = constants.OAUTH_BASE_PATH; @@ -45,4 +46,21 @@ var JWTAuth = () => { }); }; -module.exports = { JWTAuth }; +const ValidatePdf = (tempFile) => { + const parser = new PdfParser(); + return new Promise(function (resolve, reject) { + parser.on('pdfParser_dataError', (errData) => { + console.error(errData.parserError); + reject(new Error([ + 'Unable to parse downloaded PDF\n', + JSON.stringify(errData) + ])); + }); + parser.on('pdfParser_dataReady', (data) => { + resolve(true); + }); + parser.loadPDF(tempFile); + }); +}; + +module.exports = { JWTAuth, ValidatePdf };