diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a615d7d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Folders +.idea +node_modules + +# Files +**/privateKey.pem +**/publicKey.pem +**/development.json +**/sandbox.json +**/snippet.js \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..e9bad019 --- /dev/null +++ b/.npmignore @@ -0,0 +1,11 @@ +# This file is written to be a whitelist instead of a blacklist. Start by +# ignoring everything, then add back the files we want to be included in the +# final NPM package. +* + +# And these are the files that are allowed. +!/LICENSE +!/README.md +!/package.json +!/index.js +!/sdk/**/**/* diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..19d17cda --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to the following versioning pattern: + +Given a version number MAJOR.MINOR.PATCH, increment: + +- MAJOR version when the **API** version is incremented. This may include backwards incompatible changes; +- MINOR version when **breaking changes** are introduced OR **new functionalities** are added in a backwards compatible manner; +- PATCH version when backwards compatible bug **fixes** are implemented. + +## [Unreleased] +### Added +- Full Stark Bank API v2 compatibility diff --git a/README.md b/README.md index 2e52bda7..910cd9d1 100644 --- a/README.md +++ b/README.md @@ -1 +1,943 @@ -# sdk-node \ No newline at end of file +# Stark Bank Node SDK Beta + +Welcome to the Stark Bank Node SDK! This tool is made for Node +developers who want to easily integrate with our API. +This SDK version is compatible with the Stark Bank API v2. + +If you have no idea what Stark Bank is, check out our [website](https://www.starkbank.com/) +and discover a world where receiving or making payments +is as easy as sending a text message to your client! + +## Help and Feedback + +If you have any questions about our SDK, just email us your questions. +We will respond you quickly, pinky promise. We are here to help you integrate with us ASAP. +We also love feedback, so don't be shy about sharing your thoughts with us. + +Email: developers@starkbank.com + +## Supported Node Versions + +This library supports the following Node versions: + +* Node 10+ + +If you have specific version demands for your projects, feel free to contact us. + +## Stark Bank API Reference + +Feel free to take a look at our [API docs](https://www.starkbank.com/docs/api). + +## Versioning + +This project adheres to the following versioning pattern: + +Given a version number MAJOR.MINOR.PATCH, increment: + +- MAJOR version when the **API** version is incremented. This may include backwards incompatible changes; +- MINOR version when **breaking changes** are introduced OR **new functionalities** are added in a backwards compatible manner; +- PATCH version when backwards compatible bug **fixes** are implemented. + +## Setup + +### 1. Install our SDK + +1.1 To install the package with npm, run: + +```sh +npm install starkbank +``` + +### 2. Create your Private and Public Keys + +We use ECDSA. That means you need to generate a secp256k1 private +key to sign your requests to our API, and register your public key +with us so we can validate those requests. + +You can use one of following methods: + +2.1. Check out the options in our [tutorial](https://starkbank.com/faq/how-to-create-ecdsa-keys). + +2.2. Use our SDK: + +```javascript +const starkbank = require('starkbank'); + +let privateKey, publicKey; + +[privateKey, publicKey] = starkbank.key.create(); + +// or, to also save .pem files in a specific path +[privateKey, publicKey] = starkbank.key.create("file/keys/"); +``` + +### 3. Create a Project + +You need a project for direct API integrations. To create one in Sandbox: + +3.1. Log into [Starkbank Sandbox](https://sandbox.web.starkbank.com) + +3.2. Go to Menu > Usuários (Users) > Projetos (Projects) + +3.3. Create a Project: Give it a name and upload the public key you created in section 2. + +3.4. After creating the Project, get its Project ID + +3.5. Use the Project ID and private key to create the object below: + +```javascript +const starkbank = require('starkbank'); + +// Get your private key from an environment variable or an encrypted database. +// This is only an example of a private key content. You should use your own key. +let privateKeyContent = ` +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIMCwW74H6egQkTiz87WDvLNm7fK/cA+ctA2vg/bbHx3woAcGBSuBBAAK +oUQDQgAE0iaeEHEgr3oTbCfh8U2L+r7zoaeOX964xaAnND5jATGpD/tHec6Oe9U1 +IF16ZoTVt1FzZ8WkYQ3XomRD4HS13A== +-----END EC PRIVATE KEY----- +`; + +let project = new starkbank.Project({ + environment: 'sandbox', + id: '5656565656565656', + privateKey: privateKeyContent +}); +``` + +NOTE 1: Never hard-code your private key. Get it from an environment variable or an encrypted database. + +NOTE 2: We support `'sandbox'` and `'production'` as environments. + +NOTE 3: The project you created in `sandbox` does not exist in `production` and vice versa. + + +### 4. Setting up the user + +There are two kinds of users that can access our API: **Project** and **Member**. + +- `Member` is the one you use when you log into our webpage with your e-mail. +- `Project` is designed for integrations and is the one meant for our SDK. + +There are two ways to inform the user to the SDK: + +4.1 Passing the user as argument in all functions: + +```javascript +const starkbank = require('starkbank'); +(async() => { + let balance = await starkbank.balance.get({user: project}); +})(); +``` + +4.2 Set it as a default user in the SDK: + +```javascript +const starkbank = require('starkbank'); + +starkbank.user = project; + +(async() => { + let balance = await starkbank.balance.get(); +})(); +``` + +Just select the way of passing the project user that is more convenient to you. +On all following examples we will assume a default user has been set. + +## Testing in Sandbox + +Your initial balance is zero. For many operations in Stark Bank, you'll need funds +in your account, which can be added to your balance by creating a Boleto. + +In the Sandbox environment, 90% of the created Boletos will be automatically paid, +so there's nothing else you need to do to add funds to your account. Just create +a few and wait around a bit. + +In Production, you (or one of your clients) will need to actually pay this Boleto +for the value to be credited to your account. + + +## Usage + +Here are a few examples on how to use the SDK. If you have any doubts, use the built-in +`help()` function to get more info on the desired functionality +(for example: `help(starkbank.boleto.create)`) + +### Get balance + +To know how much money you have in your workspace, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let balance = await starkbank.balance.get(); + console.log(balance); +})(); +``` + +### Create boletos + +You can create boletos to charge customers or to receive money from accounts +you have in other banks. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let boletos = await starkbank.boleto.create([ + { + amount: 23571, // R$ 235,71 + name: 'Buzz Aldrin', + taxId: '012.345.678-90', + streetLine1: 'Av. Paulista, 200', + streetLine2: '10 andar', + district: 'Bela Vista', + city: 'São Paulo', + stateCode: 'SP', + zipCode: '01310-000', + due: '2020-04-30', + fine: 5, // 5% + interest: 2.5, // 2.5% per month + }, + ]); + + for (let boleto of boletos) { + console.log(boleto); + } +})(); +``` + +### Query boletos + +You can get a list of created boletos given some filters. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let boletos = await starkbank.boleto.query({ + limit: 150, + after: '2020-03-01', + before: '2020-03-30', + }); + + for await (let boleto of boletos) { + console.log(boleto); + } +})(); +``` + +### Get boleto + +After its creation, information on a boleto may be retrieved by passing its id. +Its status indicates whether it's been paid. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let boleto = await starkbank.boleto.get('5155165527080960') + console.log(boleto); +})(); +``` + +### Get boleto PDF + +After its creation, a boleto PDF may be retrieved by passing its id. + +```javascript +const starkbank = require('starkbank'); +const fs = require('fs').promises; + +(async() => { + let pdf = await starkbank.boleto.pdf('5155165527080960'); + await fs.writeFile('boleto.pdf', pdf); +})(); +``` + +Be careful not to accidentally enforce any encoding on the raw pdf content, +as it may yield abnormal results in the final file, such as missing images +and strange characters. + +### Delete boleto + +You can also cancel a boleto by its id. +Note that this is not possible if it has been processed already. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let boleto = await starkbank.boleto.delete('5155165527080960'); + console.log(boleto); +})(); +``` + +### Query boleto logs + +Logs are pretty important to understand the life cycle of a boleto. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let logs = await starkbank.boleto.log.query({limit: 100}); + + for await (let log of logs) { + console.log(log); + } +})(); +``` + +### Get a boleto log + +You can get a single log by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let log = await starkbank.boleto.log.get('5155165527080960'); + console.log(log); +})(); +``` + +### Create transfers + +You can also create transfers in the SDK (TED/DOC). + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transfers = await starkbank.transfer.create([ + { + amount: 100, + bankCode: '033', + branchCode: '0001', + accountNumber: '10000-0', + taxId: '276.685.415-00', + name: 'Tony Stark', + tags: ['iron', 'suit'] + }, + { + amount: 200, + bankCode: '341', + branchCode: '1234', + accountNumber: '123456-7', + taxId: '372.864.795-04', + name: 'Jon Snow', + tags: [] + } + ]) + + for (let transfer of transfers) { + console.log(transfer); + } +})(); +``` + +### Query transfers + +You can query multiple transfers according to filters. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transfers = await starkbank.transfer.query({ + after: '2020-03-01', + before: '2020-03-30', + }); + + for await (let transfer of transfers) { + console.log(transfer); + } +})(); +``` + +### Get transfer + +To get a single transfer by its id, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transfer = await starkbank.transfer.get('5155165527080960'); + console.log(transfer); +})(); +``` + +### Get transfer PDF + +After its creation, a transfer PDF may also be retrieved by passing its id. + +```javascript +const starkbank = require('starkbank'); +const fs = require('fs').promises; + +(async() => { + let pdf = await starkbank.transfer.pdf('5155165527080960'); + await fs.writeFile('transfer.pdf', pdf); +})(); +``` + +Be careful not to accidentally enforce any encoding on the raw pdf content, +as it may yield abnormal results in the final file, such as missing images +and strange characters. + +### Query transfer logs + +You can query transfer logs to better understand transfer life cycles. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let logs = await starkbank.transfer.log.query({limit: 50}); + + for await (let log of logs) { + console.log(log); + } +})(); +``` + +### Get a transfer log + +You can also get a specific log by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let log = await starkbank.boleto.log.get('5155165527080960'); + console.log(log); +})(); +``` + +### Pay a boleto + +Paying boletos is also simple. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payments = await starkbank.boletoPayment.create([ + { + taxId: "012.345.678-90", + description: "take my money", + scheduled: "2023-03-13", + line: "34191.09008 64694.017308 71444.640008 1 96610000014500", + tags: ["take", "my", "money"], + }, + { + taxId: "012.345.678-90", + description: "take my money one more time", + scheduled: "2023-03-14", + barCode: "34191972300000289001090064694197307144464000", + tags: ["again"], + }, + ]) + + for (let payment of payments) { + console.log(payment); + } +})(); +``` + +### Get boleto payment + +To get a single boleto payment by its id, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payment = await starkbank.boletoPayment.get('5155165527080960'); + console.log(payment); +})(); +``` + +### Get boleto payment PDF + +After its creation, a boleto payment PDF may be retrieved by passing its id. + +```javascript +const starkbank = require('starkbank'); +const fs = require('fs').promises; + +(async() => { + let pdf = await starkbank.boletoPayment.pdf('5155165527080960'); + await fs.writeFile('boleto-payment.pdf', pdf); +})(); +``` + +Be careful not to accidentally enforce any encoding on the raw pdf content, +as it may yield abnormal results in the final file, such as missing images +and strange characters. + +### Delete boleto payment + +You can also cancel a boleto payment by its id. +Note that this is not possible if it has been processed already. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payment = await starkbank.boletoPayment.delete('5155165527080960'); + console.log(payment); +})(); +``` + +### Query boleto payments + +You can search for boleto payments using filters. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payments = await starkbank.boletoPayment.query({ + after: '2020-03-01', + before: '2020-03-30', + }); + + for await (let payment of payments) { + console.log(payment); + } +})(); +``` + +### Query boleto payment logs + +Searches are also possible with boleto payment logs: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let logs = await starkbank.boletoPayment.log.query({ + after: '2020-03-01', + before: '2020-03-30', + }); + + for await (let log of logs) { + console.log(log); + } +})(); +``` + + +### Get boleto payment log + +You can also get a boleto payment log by specifying its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let log = await starkbank.boletoPayment.log.get('5155165527080960'); + console.log(log); +})(); +``` + +### Create utility payment + +Its also simple to pay utility bills (such electricity and water bills) in the SDK. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payments = await starkbank.utilityPayment.create([ + { + line: "83680000001 7 08430138003 0 71070987611 8 00041351685 7", + scheduled: "2020-03-13", + description: "take my money", + tags: ["take", "my", "money"], + }, + { + barCode: "83600000001522801380037107172881100021296561", + scheduled: "2020-03-14", + description: "take my money one more time", + tags: ["again"], + }, + ]); + + for await (let payment of payments) { + console.log(payment); + } +})(); +``` + +### Query utility payments + +To search for utility payments using filters, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payments = await starkbank.utilityPayment.query({ + tags: ["electricity", "gas"], + }); + + for await (let payment of payments) { + console.log(payment); + } +})(); +``` + +### Get utility payment + +You can get a specific bill by its id: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payment = await starkbank.utilityPayment.get('5155165527080960'); + console.log(payment); +})(); +``` + +### Get utility payment PDF + +After its creation, a utility payment PDF may also be retrieved by passing its id. + +```javascript +const starkbank = require('starkbank'); +const fs = require('fs').promises; + +(async() => { + let pdf = await starkbank.utilityPayment.pdf('5155165527080960'); + await fs.writeFile('utility-payment.pdf', pdf); +})(); +``` + +Be careful not to accidentally enforce any encoding on the raw pdf content, +as it may yield abnormal results in the final file, such as missing images +and strange characters. + +### Delete utility payment + +You can also cancel a utility payment by its id. +Note that this is not possible if it has been processed already. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let payment = await starkbank.utilityPayment.delete('5155165527080960'); + console.log(payment); +})(); +``` + +### Query utility bill payment logs + +You can search for payment logs by specifying filters. Use this to understand the +bills life cycles. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let logs = await starkbank.utilityPayment.log.query({ + paymentIds:["102893710982379182", "92837912873981273"], + }); + + for await (let log of logs) { + console.log(log); + } +})(); +``` + +### Get utility bill payment log + +If you want to get a specific payment log by its id, just run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let log = await starkbank.utilityPayment.log.get('5155165527080960'); + console.log(log); +})(); +``` + +### Create transactions + +To send money between Stark Bank accounts, you can create transactions: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transactions = await starkbank.transaction.create([ + { + amount: 100, // (R$ 1.00) + receiverId: "1029378109327810", + description: "Transaction to dear provider", + externalId: "12345", // so we can block anything you send twice by mistake + tags: ["provider"] + }, + { + amount: 234, // (R$ 2.34) + receiverId: "2093029347820947", + description: "Transaction to the other provider", + externalId: "12346", // so we can block anything you send twice by mistake + tags: ["provider"] + }, + ]) + + for (let transaction of transactions) { + console.log(transaction); + } +})(); +``` + +### Query transactions + +To understand your balance changes (bank statement), you can query +transactions. Note that our system creates transactions for you when +you receive boleto payments, pay a bill or make transfers, for example. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transactions = await starkbank.transaction.query({ + after: "2020-01-01", + before: "2020-03-01", + }); + + for await (let transaction of transactions) { + console.log(transaction); + } +})(); +``` + +### Get transaction + +You can get a specific transaction by its id: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let transaction = await starkbank.transaction.get('5155165527080960'); + console.log(transaction); +})(); +``` + +### Create webhook subscription + +To create a webhook subscription and be notified whenever an event occurs, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let webhook = await starkbank.webhook.create({ + url: "https://webhook.site/dd784f26-1d6a-4ca6-81cb-fda0267761ec", + subscriptions: ["transfer", "boleto", "boleto-payment", "utility-payment"], + }); + + console.log(webhook); +})(); +``` + +### Query webhooks + +To search for registered webhooks, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let webhooks = await starkbank.webhook.query(); + + for await (let webhook of webhooks) { + console.log(webhook); + } +})(); +``` + +### Get webhook + +You can get a specific webhook by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let webhook = await starkbank.webhook.get('5155165527080960'); + console.log(webhook); +})(); +``` + +### Delete webhook + +You can also delete a specific webhook by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let webhook = await starkbank.webhook.delete('5155165527080960'); + console.log(webhook); +})(); +``` + +### Process webhook events + +Its easy to process events that arrived in your webhook. Remember to pass the +signature header so the SDK can make sure its really StarkBank that sent you +the event. + +```javascript +const starkbank = require('starkbank'); +const express = require('express') +const app = express() + +app.use(express.json()) +const port = 3000 +app.post('/', async (req, res) => { + try { + let event = await starkbank.event.parse({ + content: request.body, + signature: request.headers["Digital-Signature"] + }); + if (event.subscription === "transfer") { + console.log(event.log.transfer); + } else if (event.subscription === "boleto") { + console.log(event.log.boleto); + } else if (event.subscription === "boleto-payment") { + console.log(event.log.payment); + } else if (event.subscription === "utility-payment") { + console.log(event.log.payment); + } + res.end() + } + catch (err) { + console.log(err) + res.status(400).end() + } +}) +app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`)) +``` + +### Query webhook events + +To search for webhooks events, run: + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let events = await starkbank.event.query({ + after: "2020-01-01", + before: "2020-03-01", + }); + + for await (let event of events) { + console.log(event); + } +})(); +``` + +### Get webhook event + +You can get a specific webhook event by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let event = await starkbank.event.get('5155165527080960'); + console.log(event); +})(); +``` + +### Delete webhook event + +You can also delete a specific webhook event by its id. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let event = await starkbank.event.delete('5155165527080960'); + console.log(event); +})(); +``` + +### Set webhook events as delivered + +This can be used in case you've lost events. +With this function, you can manually set events retrieved from the API as +"delivered" to help future event queries with `isDelivered=false`. + +```javascript +const starkbank = require('starkbank'); + +(async() => { + let event = await starkbank.event.update('5155165527080960', {isDelivered: true}); + console.log(event); +})(); +``` + +## Handling errors + +The SDK may raise one of four types of errors: __InputErrors__, __InternalServerError__, __UnknownException__, __InvalidSignatureException__ + +__InputErrors__ will be raised whenever the API detects an error in your request (status code 400). +If you catch such an error, you can get its elements to verify each of the +individual errors that were detected in your request by the API. +For example: + +```javascript +const starkbank = require('starkbank'); +const { InputErrors } = starkbank.errors; + +(async() => { + try{ + let transactions = await starkbank.transaction.create([ + { + amount: 100, + receiverId: "1029378109327810", + description: ".", + externalId: "12345", + tags: ["provider"] + }, + ]); + } catch (e) { + if (e instanceof InputErrors) { + for (error of e.errors) { + console.log(error.code, error.message); + } + } else { + throw e; + } + } +})(); +``` + +__InternalServerError__ will be raised if the API runs into an internal error. +If you ever stumble upon this one, rest assured that the development team +is already rushing in to fix the mistake and get you back up to speed. + +__UnknownException__ will be raised if a request encounters an error that is +neither __InputErrors__ nor an __InternalServerError__, such as connectivity problems. + +__InvalidSignatureException__ will be raised specifically by starkbank.event.parse() +when the provided content and signature do not check out with the Stark Bank public +key. diff --git a/index.js b/index.js new file mode 100644 index 00000000..f9657cd2 --- /dev/null +++ b/index.js @@ -0,0 +1,27 @@ +exports.version = '0.1.0'; +exports.cache = {}; +exports.user = null + +// Modules +exports.transaction = require('./sdk/transaction'); +exports.balance = require('./sdk/balance'); +exports.boleto = require('./sdk/boleto'); +exports.transfer = require('./sdk/transfer'); +exports.boletoPayment = require('./sdk/boletoPayment'); +exports.utilityPayment = require('./sdk/utilityPayment'); +exports.webhook = require('./sdk/webhook'); +exports.event = require('./sdk/event'); +exports.key = require('./sdk/key.js'); +exports.error = require('./sdk/error.js'); + + +// Classes +exports.Project = require('./sdk/user').Project; +exports.Transaction = exports.transaction.Transaction; +exports.Balance = exports.balance.Balance; +exports.Boleto = exports.boleto.Boleto; +exports.BoletoPayment = exports.boletoPayment.BoletoPayment; +exports.UtilityPayment = exports.utilityPayment.UtilityPayment; +exports.Transfer = exports.transfer.Transfer; +exports.Webhook = exports.webhook.Webhook; +exports.Event = exports.event.Event; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..c797886c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1138 @@ +{ + "name": "starkbank", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@sindresorhus/is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", + "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==" + }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "12.12.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", + "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==" + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "cacheable-lookup": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", + "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", + "requires": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + } + }, + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", + "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, + "defer-to-connect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "got": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", + "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "requires": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "keyv": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", + "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", + "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.3", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==" + }, + "p-event": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", + "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", + "requires": { + "p-timeout": "^2.0.1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "starkbank-ecdsa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/starkbank-ecdsa/-/starkbank-ecdsa-1.0.0.tgz", + "integrity": "sha512-e5Md1Sd050Z7O3hISBq/nuufwMcH5b2niSS5nSLrkobcGu8SZqVzyVI1aJs2akIIV3bBl2zxFS9axtS6LKE6Sw==", + "requires": { + "big-integer": "^1.6.48", + "js-sha256": "^0.9.0", + "mocha": "^6.2.2" + }, + "dependencies": { + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "requires": { + "chalk": "^2.0.1" + } + }, + "mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", + "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.4", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-readable-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", + "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + } + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..89135d18 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "starkbank", + "version": "0.1.0", + "description": "SDK to facilitate Node integrations with Stark Bank", + "main": "index.js", + "directories": { + "lib": "sdk", + "test": "tests" + }, + "scripts": { + "test": "mocha tests --timeout 20000" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/starkbank/sdk-node.git" + }, + "keywords": [ + "ecdsa", + "signature", + "sdk", + "stark", + "starkbank", + "openbanking" + ], + "author": "Stark Bank", + "license": "MIT", + "bugs": { + "url": "https://github.com/starkbank/sdk-node/issues" + }, + "homepage": "https://github.com/starkbank/ecdsa-node#readme", + "dependencies": { + "starkbank-ecdsa": "^1.0.0", + "got": "^10.7.0" + }, + "devDependencies": { + "decamelize": "^4.0.0", + "mocha": "^7.1.1" + } +} diff --git a/sdk/balance/balance.js b/sdk/balance/balance.js new file mode 100644 index 00000000..bc27b760 --- /dev/null +++ b/sdk/balance/balance.js @@ -0,0 +1,50 @@ +const rest = require('../utils/rest.js'); +const Resource = require('../utils/resource.js').Resource + + +class Balance extends Resource { + /** + * + * Balance object + * + * The Balance object displays the current balance of the workspace, + * which is the result of the sum of all transactions within this + * workspace. The balance is never generated by the user, but it + * can be retrieved to see the information available. + * + * Attributes (return-only): + * id [string, default null]: unique id returned when Boleto is created. ex: '5656565656565656' + * amount [integer, default null]: current balance amount of the workspace in cents. ex: 200 (= R$ 2.00) + * currency [string, default null]: currency of the current workspace. Expect others to be added eventually. ex: 'BRL' + * updated [string, default null]: update datetime for the balance. ex: '2020-03-10 10:30:00.000' + * + */ + constructor(id, amount, currency, updated) { + super(id); + this.amount = amount; + this.currency = currency; + this.updated = updated; + } +} + +exports.Balance = Balance; +let resource = {'class': exports.Balance, 'name': 'Balance'}; + + +exports.get = async function ({user} = {}) { + /** + * + * Retrieve the Balance object + * + * Receive the Balance object linked to your workspace in the Stark Bank API + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Balance object with updated attributes + * + */ + let balance = await rest.getList(resource, 100, user).next(); + return balance['value']; +}; diff --git a/sdk/balance/index.js b/sdk/balance/index.js new file mode 100644 index 00000000..a56a48fb --- /dev/null +++ b/sdk/balance/index.js @@ -0,0 +1 @@ +exports.get = require('./balance.js').get; \ No newline at end of file diff --git a/sdk/boleto/boleto.js b/sdk/boleto/boleto.js new file mode 100644 index 00000000..710afa57 --- /dev/null +++ b/sdk/boleto/boleto.js @@ -0,0 +1,183 @@ +const rest = require('../utils/rest.js'); +const check = require('../utils/check.js'); +const Resource = require('../utils/resource.js').Resource + + +class Boleto extends Resource { + /** + * + * Boleto object + * + * When you initialize a Boleto, the entity will not be automatically + * sent to the Stark Bank API. The 'create' function sends the objects + * to the Stark Bank API and returns the list of created objects. + * + * Parameters (required): + * amount [integer]: Boleto value in cents. Minimum = 200 (R$2,00). ex: 1234 (= R$ 12.34) + * name [string]: payer full name. ex: 'Anthony Edward Stark' + * taxId [string]: payer tax ID (CPF or CNPJ) with or without formatting. ex: '01234567890' or '20.018.183/0001-80' + * streetLine1 [string]: payer main address. ex: Av. Paulista, 200 + * streetLine2 [string]: payer address complement. ex: Apto. 123 + * district [string]: payer address district / neighbourhood. ex: Bela Vista + * city [string]: payer address city. ex: Rio de Janeiro + * stateCode [string]: payer address state. ex: GO + * zipCode [string]: payer address zip code. ex: 01311-200 + * due [string, default today + 2 days]: Boleto due date in ISO format. ex: 2020-04-30 + * + * Parameters (optional): + * fine [float, default 0.0]: Boleto fine for overdue payment in %. ex: 2.5 + * interest [float, default 0.0]: Boleto monthly interest for overdue payment in %. ex: 5.2 + * overdueLimit [integer, default 59]: limit in days for automatic Boleto cancellation after due date. ex: 7 (max: 59) + * descriptions [list of dictionaries, default null]: list of dictionaries with 'text':string and (optional) 'amount':int pairs + * tags [list of strings]: list of strings for tagging + * + * Attributes (return-only): + * id [string, default null]: unique id returned when Boleto is created. ex: '5656565656565656' + * fee [integer, default null]: fee charged when Boleto is paid. ex: 200 (= R$ 2.00) + * line [string, default null]: generated Boleto line for payment. ex: '34191.09008 63571.277308 71444.640008 5 81960000000062' + * barCode [string, default null]: generated Boleto bar-code for payment. ex: '34195819600000000621090063571277307144464000' + * status [string, default null]: current Boleto status. ex: 'registered' or 'paid' + * created [string, default null]: creation datetime for the Boleto. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ + amount, name, taxId, streetLine1, streetLine2, district, city, stateCode, zipCode, + due = null, fine = null, interest = null, overdueLimit = null, + tags = null, descriptions = null, id = null, fee = null, line = null, + barCode = null, status = null, created = null + }) { + super(id); + this.amount = amount; + this.name = name; + this.taxId = taxId; + this.streetLine1 = streetLine1; + this.streetLine2 = streetLine2; + this.district = district; + this.city = city; + this.stateCode = stateCode; + this.zipCode = zipCode; + this.due = check.date(due); + this.fine = fine; + this.interest = interest; + this.overdueLimit = overdueLimit; + this.tags = tags; + this.descriptions = descriptions; + this.fee = fee; + this.line = line; + this.barCode = barCode; + this.status = status; + this.created = created; + } +} + +exports.Boleto = Boleto; +let resource = {'class': exports.Boleto, 'name': 'Boleto'}; + +exports.create = async function (boletos, {user} = {}) { + /** + * + * Create Boletos + * + * Send a list of Boleto objects for creation in the Stark Bank API + * + * Parameters (required): + * boletos [list of Boleto objects]: list of Boleto objects to be created in the API + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of Boleto objects with updated attributes + * + */ + return rest.post(resource, boletos, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Boleto + * + * Receive a single Boleto object previously created in the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * Return: + * Boleto object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.pdf = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Boleto pdf file + * + * Receive a single Boleto pdf file generated in the Stark Bank API by passing its id. + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Boleto pdf file + * + */ + return rest.getPdf(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, status, tags, ids, user} = {}) { + /** + * + * Retrieve Boletos + * + * Receive a generator of Boleto objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * status [string, default null]: filter for status of retrieved objects. ex: 'paid' or 'registered' + * tags [list of strings, default null]: tags to filter retrieved objects. ex: ['tony', 'stark'] + * ids [list of strings, default null]: list of ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of Boleto objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + status: status, + tags: tags, + ids: ids, + }; + return rest.getList(resource, query, user); +}; + +exports.delete = async function (id, {user} = {}) { + /** + * + * Delete a Boleto entity + * + * Delete a Boleto entity previously created in the Stark Bank API + * + * Parameters (required): + * id [string]: Boleto unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * deleted Boleto with updated attributes + * + */ + return rest.deleteId(resource, id, user); +}; \ No newline at end of file diff --git a/sdk/boleto/index.js b/sdk/boleto/index.js new file mode 100644 index 00000000..bdbd1470 --- /dev/null +++ b/sdk/boleto/index.js @@ -0,0 +1,9 @@ +const boleto = require('./boleto.js'); + +exports.log = require('./log'); +exports.create = boleto.create; +exports.delete = boleto.delete; +exports.query = boleto.query; +exports.get = boleto.get; +exports.pdf = boleto.pdf; +exports.Boleto = boleto.Boleto; diff --git a/sdk/boleto/log/index.js b/sdk/boleto/log/index.js new file mode 100644 index 00000000..2d09e326 --- /dev/null +++ b/sdk/boleto/log/index.js @@ -0,0 +1,4 @@ +const log = require('./log.js'); + +exports.get = log.get; +exports.query = log.query; \ No newline at end of file diff --git a/sdk/boleto/log/log.js b/sdk/boleto/log/log.js new file mode 100644 index 00000000..36234c4b --- /dev/null +++ b/sdk/boleto/log/log.js @@ -0,0 +1,84 @@ +const rest = require('../../utils/rest.js'); +const check = require('../../utils/check.js'); +const Resource = require('../../utils/resource.js').Resource + + +class Log extends Resource { + /** + * + * Boleto Log object + * + * Every time a Boleto entity is updated, a corresponding Boleto Log + * is generated for the entity. This log is never generated by the + * user, but it can be retrieved to check additional information + * on the Boleto. + * + * Attributes: + * id [string]: unique id returned when the log is created. ex: '5656565656565656' + * boleto [Boleto]: Boleto entity to which the log refers to. + * errors [list of strings]: list of errors linked to this Boleto event + * type [string]: type of the Boleto event which triggered the log creation. ex: 'registered' or 'paid' + * created [string]: creation datetime for the boleto. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ created, type, errors, boleto, id }) { + super(id); + this.created = check.date(created); + this.type = type; + this.errors = errors; + this.boleto = boleto; + } +} + +exports.Log = Log; +let resource = {'class': exports.Log, 'name': 'BoletoLog'}; + + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Boleto Log + * + * Receive a single Boleto Log object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Boleto Log object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, types, boletoIds, user} = {}) { + /** + * + * Retrieve Boleto Logs + * + * Receive a generator of Boleto Log objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * types [list of strings, default null]: filter for log event types. ex: 'paid' or 'registered' + * boletoIds [list of strings, default null]: list of Boleto ids to filter logs. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of Boleto Log objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + types: types, + boletoIds: boletoIds, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/boletoPayment/boletoPayment.js b/sdk/boletoPayment/boletoPayment.js new file mode 100644 index 00000000..3131d5cc --- /dev/null +++ b/sdk/boletoPayment/boletoPayment.js @@ -0,0 +1,163 @@ +const rest = require('../utils/rest.js'); +const check = require('../utils/check.js'); +const Resource = require('../utils/resource.js').Resource + + +class BoletoPayment extends Resource { + /** + * + * BoletoPayment object + * + * When you initialize a BoletoPayment, the entity will not be automatically + * created in the Stark Bank API. The 'create' function sends the objects + * to the Stark Bank API and returns the list of created objects. + * + * Parameters (conditionally required): + * line [string, default null]: Number sequence that describes the payment. Either 'line' or 'bar_code' parameters are required. If both are sent, they must match. ex: '34191.09008 63571.277308 71444.640008 5 81960000000062' + * barCode [string, default null]: Bar code number that describes the payment. Either 'line' or 'barCode' parameters are required. If both are sent, they must match. ex: '34195819600000000621090063571277307144464000' + * + * Parameters (required): + * taxId [string]: receiver tax ID (CPF or CNPJ) with or without formatting. ex: '01234567890' or '20.018.183/0001-80' + * description [string]: Text to be displayed in your statement (min. 10 characters). ex: 'payment ABC' + * + * Parameters (optional): + * scheduled [string, default today]: payment scheduled date. ex: '2020-03-10' + * tags [list of strings]: list of strings for tagging + * + * Attributes (return-only): + * id [string, default null]: unique id returned when payment is created. ex: '5656565656565656' + * status [string, default null]: current payment status. ex: 'registered' or 'paid' + * amount [int, default null]: amount automatically calculated from line or bar_code. ex: 23456 (= R$ 234.56) + * fee [integer, default null]: fee charged when boleto payment is created. ex: 200 (= R$ 2.00) + * created [string, default null]: creation datetime for the payment. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ taxId, description, scheduled, line, barCode, tags, id, status, amount, fee, created }) { + super(id); + this.taxId = taxId; + this.description = description; + this.line = line; + this.barCode = barCode; + this.scheduled = check.date(scheduled); + this.tags = tags; + this.status = status; + this.amount = amount; + this.fee = fee; + this.created = created; + } +} + +exports.BoletoPayment = BoletoPayment; +let resource = {'class': exports.BoletoPayment, 'name': 'BoletoPayment'}; + +exports.create = async function (payments, {user} = {}) { + /** + * + * Create BoletoPayments + * + * Send a list of BoletoPayment objects for creation in the Stark Bank API + * + * Parameters (required): + * payments [list of BoletoPayment objects]: list of BoletoPayment objects to be created in the API + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of BoletoPayment objects with updated attributes + * + */ + return rest.post(resource, payments, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific BoletoPayment + * + * Receive a single BoletoPayment object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * BoletoPayment object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.pdf = async function (id, {user} = {}) { + /** + * + * Retrieve a specific BoletoPayment pdf file + * + * Receive a single BoletoPayment pdf file generated in the Stark Bank API by passing its id. + * Only valid for boleto payments with 'success' status. + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * BoletoPayment pdf file + * + */ + return rest.getPdf(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, tags, ids, status, user} = {}) { + /** + * + * Retrieve BoletoPayments + * + * Receive a generator of BoletoPayment objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * tags [list of strings, default null]: tags to filter retrieved objects. ex: ['tony', 'stark'] + * ids [list of strings, default null]: list of ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * status [string, default null]: filter for status of retrieved objects. ex: 'paid' + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of BoletoPayment objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + tags: tags, + ids: ids, + status: status, + }; + return rest.getList(resource, query, user); +}; + +exports.delete = async function (id, {user} = {}) { + /** + * + * Delete a BoletoPayment entity + * + * Delete a BoletoPayment entity previously created in the Stark Bank API + * + * Parameters (required): + * id [string]: BoletoPayment unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * deleted BoletoPayment with updated attributes + * + */ + return rest.deleteId(resource, id, user); +}; \ No newline at end of file diff --git a/sdk/boletoPayment/index.js b/sdk/boletoPayment/index.js new file mode 100644 index 00000000..a1e21520 --- /dev/null +++ b/sdk/boletoPayment/index.js @@ -0,0 +1,9 @@ +boletoPayment = require('./boletoPayment.js'); + +exports.log = require('./log'); +exports.create = boletoPayment.create; +exports.delete = boletoPayment.delete; +exports.query = boletoPayment.query; +exports.get = boletoPayment.get; +exports.pdf = boletoPayment.pdf; +exports.BoletoPayment = boletoPayment.BoletoPayment; \ No newline at end of file diff --git a/sdk/boletoPayment/log/index.js b/sdk/boletoPayment/log/index.js new file mode 100644 index 00000000..2d09e326 --- /dev/null +++ b/sdk/boletoPayment/log/index.js @@ -0,0 +1,4 @@ +const log = require('./log.js'); + +exports.get = log.get; +exports.query = log.query; \ No newline at end of file diff --git a/sdk/boletoPayment/log/log.js b/sdk/boletoPayment/log/log.js new file mode 100644 index 00000000..1d28f74b --- /dev/null +++ b/sdk/boletoPayment/log/log.js @@ -0,0 +1,83 @@ +const rest = require('../../utils/rest.js'); +const Resource = require('../../utils/resource.js').Resource + + +class Log extends Resource { + /** + * + * BoletoPayment Log object + * + * Every time a BoletoPayment entity is modified, a corresponding BoletoPayment Log + * is generated for the entity. This log is never generated by the + * user, but it can be retrieved to check additional information + * on the BoletoPayment. + * + * Attributes: + * id [string]: unique id returned when the log is created. ex: '5656565656565656' + * payment [BoletoPayment]: BoletoPayment entity to which the log refers to. + * errors [list of strings]: list of errors linked to this BoletoPayment event. + * type [string]: type of the BoletoPayment event which triggered the log creation. ex: 'registered' or 'paid' + * created [string]: creation datetime for the payment. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ created, type, errors, payment, id }) { + super(id); + this.created = created; + this.type = type; + this.errors = errors; + this.payment = payment; + } +} + +exports.Log = Log; +let resource = {'class': exports.Log, 'name': 'BoletoPaymentLog'}; + + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific BoletoPayment Log + * + * Receive a single BoletoPayment Log object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * BoletoPayment Log object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, types, paymentIds, user} = {}) { + /** + * + * Retrieve BoletoPayment Logs + * + * Receive a generator of BoletoPayment Log objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * types [list of strings, default null]: filter retrieved objects by event types. ex: 'paid' or 'registered' + * paymentIds [list of strings, default null]: list of BoletoPayment ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of BoletoPayment Log objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + types: types, + paymentIds: paymentIds, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/error.js b/sdk/error.js new file mode 100644 index 00000000..5d9b3dfa --- /dev/null +++ b/sdk/error.js @@ -0,0 +1,39 @@ + + +class InputError extends Error { + constructor(code, message, status = 400) { + super(message); + this.status = status; + this.code = code; + } +} + +class InputErrors extends Error { + constructor(content, status = 400) { + super(content); + this.status = status; + this.errors = []; + let errors = JSON.parse(content)['errors']; + for (let error of errors) { + this.errors.push(new InputError(error['code'], error['message'], status)); + } + } +} + +class InternalServerError extends Error { + constructor(content, status = 500) { + super(content); + this.status = status; + } +} + +class InvalidSignatureError extends Error { + constructor(message) { + super(message); + } +} + +exports.InputError = InputError; +exports.InputErrors = InputErrors; +exports.InternalServerError = InternalServerError; +exports.InvalidSignatureError = InvalidSignatureError; \ No newline at end of file diff --git a/sdk/event/event.js b/sdk/event/event.js new file mode 100644 index 00000000..70194251 --- /dev/null +++ b/sdk/event/event.js @@ -0,0 +1,174 @@ +const starkbank = require('../../index.js'); +const Ellipticcurve = require('starkbank-ecdsa'); +const Resource = require('../utils/resource.js').Resource; +const rest = require('../utils/rest.js'); +const error = require('../error.js'); + + +class Event extends Resource { + /** + * + * Webhook Event object + * + * An Event is the notification received from the subscription to the Webhook. + * Events cannot be created, but may be retrieved from the Stark Bank API to + * list all generated updates on entities. + * + * Attributes: + * id [string]: unique id returned when the log is created. ex: '5656565656565656' + * log [Log]: a Log object from one the subscription services (Transfer Log, Boleto Log, BoletoPaymentlog or UtilityPayment Log) + * created [string]: creation datetime for the notification event. ex: '2020-03-10 10:30:00.000' + * delivered [string]: delivery datetime when the notification was delivered to the user url. Will be null if no successful attempts to deliver the event occurred. ex: '2020-03-10 10:30:00.000' + * subscription [string]: service that triggered this event. ex: 'transfer', 'utility-payment' + * + */ + constructor({created, isDelivered, subscription, log, id} = {}) { + super(id); + this.log = log; + this.created = created; + this.isDelivered = isDelivered; + this.subscription = subscription; + } +} + +exports.Event = Event; +let resource = {'class': exports.Event, 'name': 'Event'}; + +async function verifySignature(content, signature, user = null, refresh = false) { + let publicKey = starkbank.cache['starkbank-public-key']; + if (!publicKey || refresh) { + let pem = await rest.getPublicKey(user); + publicKey = Ellipticcurve.PublicKey.fromPem(pem); + starkbank.cache['starkbank-public-key'] = publicKey; + } + return Ellipticcurve.Ecdsa.verify(content, signature, publicKey); +} + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific notification Event + * + * Receive a single notification Event object previously created in the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Event object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({limit, after, before, isDelivered, user} = {}) { + /** + * + * Retrieve notification Events + * + * Receive a generator of notification Event objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null]: date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null]: date filter for objects only before specified date. ex: '2020-03-10' + * isDelivered [bool, default null]: bool to filter successfully delivered events. ex: true or false + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of Event objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + isDelivered: isDelivered, + }; + return rest.getList(resource, query, user); +}; + +exports.delete = async function (id, {user} = {}) { + /** + * + * Delete notification Events + * + * Delete a list of notification Event entities previously created in the Stark Bank API + * + * Parameters (required): + * id [string]: Event unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * deleted Event with updated attributes + * + */ + return rest.deleteId(resource, id, user); +}; + +exports.update = function (id, {isDelivered, user} = {}) { + /** + * + * Set notification Event entity as delivered + * + * Set notification Event as delivered at the current timestamp (if it was not yet delivered) by passing id. + * After this is set, the event will no longer be returned on queries with isDelivered=false. + * + * Parameters (required): + * id [list of strings]: Event unique ids. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * target Event with updated attributes + * + */ + let payload = { + isDelivered: isDelivered, + }; + return rest.patchId(resource, id, payload, user); +}; + +exports.parse = async function ({content, signature, user} = {}) { + /** + * + * Create single notification Event from a content string + * + * Create a single Event object received from event listening at subscribed user endpoint. + * If the provided digital signature does not check out with the StarkBank public key, a + * starkbank.exception.InvalidSignatureException will be raised. + * + * Parameters (required): + * content [string]: response content from request received at user endpoint (not parsed) + * signature [string]: base-64 digital signature received at response header 'Digital-Signature' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Event object with updated attributes + * + */ + + let event = Object.assign(new Event(), JSON.parse(content)['event']); + + try { + signature = Ellipticcurve.Signature.fromBase64(signature); + } catch (e) { + throw new error.InvalidSignatureError('The provided signature is not valid'); + } + + if (await verifySignature(content, signature, user)) { + return event; + } + if (await verifySignature(content, signature, user, true)) { + return event; + } + throw new error.InvalidSignatureError('Provided signature and content do not match Stark Bank public key'); +}; \ No newline at end of file diff --git a/sdk/event/index.js b/sdk/event/index.js new file mode 100644 index 00000000..247d4f68 --- /dev/null +++ b/sdk/event/index.js @@ -0,0 +1,8 @@ +const event = require('./event.js'); + +exports.get = event.get; +exports.query = event.query; +exports.delete = event.delete; +exports.parse = event.parse; +exports.update = event.update; +exports.Event = event.Event; diff --git a/sdk/key.js b/sdk/key.js new file mode 100644 index 00000000..4585d894 --- /dev/null +++ b/sdk/key.js @@ -0,0 +1,21 @@ +const fs = require('fs'); +const PrivateKey = require('starkbank-ecdsa').PrivateKey; + + +exports.create = function (path = null) { + let newPrivateKey = new PrivateKey(); + let newPublicKey = newPrivateKey.publicKey(); + + let newPrivatePem = newPrivateKey.toPem(); + let newPublicPem = newPublicKey.toPem(); + + if (!path) { + fs.writeFile('private-key.pem', newPrivatePem, function (err) { + if (err) return console.log(err); + }); + fs.writeFile('public-key.pem', newPublicPem, function (err) { + if (err) return console.log(err); + }); + } + return [newPrivatePem, newPublicPem]; +}; \ No newline at end of file diff --git a/sdk/transaction/index.js b/sdk/transaction/index.js new file mode 100644 index 00000000..314f76f7 --- /dev/null +++ b/sdk/transaction/index.js @@ -0,0 +1,6 @@ +const transaction = require('./transaction.js'); + +exports.create = transaction.create; +exports.query = transaction.query; +exports.get = transaction.get; +exports.Transaction = transaction.Transaction; \ No newline at end of file diff --git a/sdk/transaction/transaction.js b/sdk/transaction/transaction.js new file mode 100644 index 00000000..cf65288c --- /dev/null +++ b/sdk/transaction/transaction.js @@ -0,0 +1,114 @@ +const rest = require('../utils/rest.js'); +const Resource = require('../utils/resource.js').Resource + + +class Transaction extends Resource { + /** + * + * Transaction object + * + * A Transaction is a transfer of funds between workspaces inside Stark Bank. + * Transactions created by the user are only for internal transactions. + * Other operations (such as transfer or charge-payment) will automatically + * create a transaction for the user which can be retrieved for the statement. + * When you initialize a Transaction, the entity will not be automatically + * created in the Stark Bank API. The 'create' function sends the objects + * to the Stark Bank API and returns the list of created objects. + * + * Parameters (required): + * amount [integer]: amount in cents to be transferred. ex: 1234 (= R$ 12.34) + * description [string]: text to be displayed in the receiver and the sender statements (Min. 10 characters). ex: 'funds redistribution' + * externalId [string]: unique id, generated by user, to avoid duplicated transactions. ex: 'transaction ABC 2020-03-30' + * receivedId [string]: unique id of the receiving workspace. ex: '5656565656565656' + * + * Parameters (optional): + * tags [list of strings]: list of strings for reference when searching transactions (may be empty). ex: ['abc', 'test'] + * Attributes (return-only): + * source [string, default null]: unique locator of the related entity in the API reference + * id [string, default null]: unique id returned when Transaction is created. ex: '7656565656565656' + * fee [integer, default null]: fee charged when transfer is created. ex: 200 (= R$ 2.00) + * created [string, default null]: creation datetime for the boleto. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ amount, description, externalId, receiverId, tags, fee, created, source, id }) { + super(id); + this.amount = amount; + this.description = description; + this.externalId = externalId; + this.receiverId = receiverId; + this.tags = tags; + this.fee = fee; + this.created = created; + this.source = source; + } +} + +exports.Transaction = Transaction; +let resource = {'class': exports.Transaction, 'name': 'Transaction'}; + +exports.create = async function (transactions, {user} = {}) { + /** + * + * Create Transactions + * + * Send a list of Transaction objects for creation in the Stark Bank API + * + * Parameters (required): + * transactions [list of Transaction objects]: list of Transaction objects to be created in the API + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of Transaction objects with updated attributes + * + */ + return rest.post(resource, transactions, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Transaction + * + * Receive a single Transaction object previously created in the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Transaction object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({limit, after, before, externalIds, user} = {}) { + /** + * + * Retrieve Transactions + * + * Receive a generator of Transaction objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects created only before specified date. ex: '2020-03-10' + * externalIds [list of strings, default null]: list of external ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of Transaction objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + externalIds: externalIds, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/transfer/index.js b/sdk/transfer/index.js new file mode 100644 index 00000000..2b466e9d --- /dev/null +++ b/sdk/transfer/index.js @@ -0,0 +1,9 @@ +transfer = require('./transfer.js'); + +exports.log = require('./log'); +exports.create = transfer.create; +exports.delete = transfer.delete; +exports.query = transfer.query; +exports.get = transfer.get; +exports.pdf = transfer.pdf; +exports.Transfer = transfer.Transfer; diff --git a/sdk/transfer/log/index.js b/sdk/transfer/log/index.js new file mode 100644 index 00000000..2d09e326 --- /dev/null +++ b/sdk/transfer/log/index.js @@ -0,0 +1,4 @@ +const log = require('./log.js'); + +exports.get = log.get; +exports.query = log.query; \ No newline at end of file diff --git a/sdk/transfer/log/log.js b/sdk/transfer/log/log.js new file mode 100644 index 00000000..4e0d9bee --- /dev/null +++ b/sdk/transfer/log/log.js @@ -0,0 +1,82 @@ +const rest = require('../../utils/rest.js'); +const Resource = require('../../utils/resource.js').Resource + + +class Log extends Resource { + /** + * + * Transfer Log object + * + * Every time a Transfer entity is modified, a corresponding Transfer Log + * is generated for the entity. This log is never generated by the + * user. + * + * Attributes: + * id [string]: unique id returned when the log is created. ex: '5656565656565656' + * transfer [Transfer]: Transfer entity to which the log refers to. + * errors [list of strings]: list of errors linked to this BoletoPayment event. + * type [string]: type of the Transfer event which triggered the log creation. ex: 'processing' or 'success' + * created [string]: creation datetime for the transfer. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ created, type, errors, transfer, id }) { + super(id); + this.created = created; + this.type = type; + this.errors = errors; + this.transfer = transfer; + } +} + +exports.Log = Log; +let resource = {'class': exports.Log, 'name': 'TransferLog'}; + + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Transfer Log + * + * Receive a single Transfer Log object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Transfer Log object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({limit, after, before, types, transferIds, user} = {}) { + /** + * + * Retrieve Transfer Logs + * + * Receive a generator of Transfer Log objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * types [list of strings, default null]: filter retrieved objects by types. ex: 'success' or 'failed' + * transferIds [list of strings, default null]: list of Transfer ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of Transfer Log objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + types: types, + transferIds: transferIds, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/transfer/transfer.js b/sdk/transfer/transfer.js new file mode 100644 index 00000000..90853387 --- /dev/null +++ b/sdk/transfer/transfer.js @@ -0,0 +1,151 @@ +const rest = require('../utils/rest.js'); +const check = require('../utils/check.js'); +const Resource = require('../utils/resource.js').Resource + + +class Transfer extends Resource { + /** + * + * Transfer object + * + * When you initialize a Transfer, the entity will not be automatically + * created in the Stark Bank API. The 'create' function sends the objects + * to the Stark Bank API and returns the list of created objects. + * + * Parameters (required): + * amount [integer]: amount in cents to be transferred. ex: 1234 (= R$ 12.34) + * name [string]: receiver full name. ex: 'Anthony Edward Stark' + * taxId [string]: receiver tax ID (CPF or CNPJ) with or without formatting. ex: '01234567890' or '20.018.183/0001-80' + * bankCode [string]: receiver 1 to 3 digits of the bank institution in Brazil. ex: '200' or '341' + * branchCode [string]: receiver bank account branch. Use '-' in case there is a verifier digit. ex: '1357-9' + * accountNumber [string]: Receiver Bank Account number. Use '-' before the verifier digit. ex: '876543-2' + * + * Parameters (optional): + * tags [list of strings]: list of strings for reference when searching for transfers. ex: ['employees', 'monthly'] + * + * Attributes (return-only): + * id [string, default null]: unique id returned when Transfer is created. ex: '5656565656565656' + * fee [integer, default null]: fee charged when transfer is created. ex: 200 (= R$ 2.00) + * status [string, default null]: current boleto status. ex: 'registered' or 'paid' + * transactionIds [list of strings, default null]: ledger transaction ids linked to this transfer (if there are two, second is the chargeback). ex: ['19827356981273'] + * created [string, default null]: creation datetime for the transfer. ex: '2020-03-10 10:30:00.000' + * updated [string, default null]: latest update datetime for the transfer. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ + amount, name, taxId, bankCode, branchCode, accountNumber, tags, + fee, status, created, updated, + transactionIds, id + }) { + super(id); + this.amount = amount; + this.name = name; + this.taxId = taxId; + this.bankCode = bankCode; + this.branchCode = branchCode; + this.accountNumber = accountNumber; + this.tags = tags; + this.fee = fee; + this.status = status; + this.created = created; + this.updated = updated; + this.transactionIds = transactionIds; + } +} + +exports.Transfer = Transfer; +let resource = {'class': exports.Transfer, 'name': 'Transfer'}; + +exports.create = async function (transfers, {user} = {}) { + /** + * + * Create Transfers + * + * Send a list of Transfer objects for creation in the Stark Bank API + * + * Parameters (required): + * transfers [list of Transfer objects]: list of Transfer objects to be created in the API + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of Transfer objects with updated attributes + * + */ + return rest.post(resource, transfers, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Transfer + * + * Receive a single Transfer object previously created in the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Transfer object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.pdf = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Transfer pdf file + * + * Receive a single Transfer pdf receipt file generated in the Stark Bank API by passing its id. + * Only valid for transfers with 'processing' and 'success' status. + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Transfer pdf file + * + */ + return rest.getPdf(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, transactionIds, status, sort, tags, user} = {}) { + /** + * + * Retrieve Transfers + * + * Receive a generator of Transfer objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null]: date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null]: date filter for objects only before specified date. ex: '2020-03-10' + * transactionIds [list of strings, default null]: list of transaction IDs linked to the desired transfers. ex: ['5656565656565656', '4545454545454545'] + * status [string, default null]: filter for status of retrieved objects. ex: 'paid' or 'registered' + * sort [string, default '-created']: sort order considered in response. Valid options are 'created', '-created', 'updated' or '-updated'. + * tags [list of strings, default null]: tags to filter retrieved objects. ex: ['tony', 'stark'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of Transfer objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + transactionIds: transactionIds, + status: status, + sort: sort, + tags: tags, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/user/index.js b/sdk/user/index.js new file mode 100644 index 00000000..0a4016a1 --- /dev/null +++ b/sdk/user/index.js @@ -0,0 +1 @@ +exports.Project = require('./project.js').Project; \ No newline at end of file diff --git a/sdk/user/project.js b/sdk/user/project.js new file mode 100644 index 00000000..0decfaa6 --- /dev/null +++ b/sdk/user/project.js @@ -0,0 +1,35 @@ +const Ecdsa = require('starkbank-ecdsa'); +const User = require('./user').User; + + +class Project extends User { + /** + * + * Project object + * + * The Project object is the main authentication entity for the SDK. + * All requests to the Stark Bank API must be authenticated via a project, + * which must have been previously created at the Stark Bank website + * [https://sandbox.web.starkbank.com] or [https://web.starkbank.com] + * before you can use it in this SDK. Projects may be passed as a parameter on + * each request or may be defined as the default user at the start (See README). + * + * Parameters (required): + * id [string]: unique id required to identify project. ex: '5656565656565656' + * privateKey [string]: PEM string of the private key linked to the project. ex: '-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEyTIHK6jYuik6ktM9FIF3yCEYzpLjO5X/\ntqDioGM+R2RyW0QEo+1DG8BrUf4UXHSvCjtQ0yLppygz23z0yPZYfw==\n-----END PUBLIC KEY-----' + * environment [string]: environment where the project is being used. ex: 'sandbox' or 'production' + * + * Attributes (return-only): + * name [string, default '']: project name. ex: 'MyProject' + * allowedIps [list of strings]: list containing the strings of the ips allowed to make requests on behalf of this project. ex: ['190.190.0.50'] + * pem [string]: private key in pem format. ex: '-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEyTIHK6jYuik6ktM9FIF3yCEYzpLjO5X/\ntqDioGM+R2RyW0QEo+1DG8BrUf4UXHSvCjtQ0yLppygz23z0yPZYfw==\n-----END PUBLIC KEY-----' + * + */ + constructor({id, privateKey, environment, name = '', allowedIps = []}) { + super({id, privateKey, environment}); + this.name = name; + this.allowedIps = allowedIps; + } +} + +exports.Project = Project; \ No newline at end of file diff --git a/sdk/user/user.js b/sdk/user/user.js new file mode 100644 index 00000000..9e252d96 --- /dev/null +++ b/sdk/user/user.js @@ -0,0 +1,23 @@ +const PrivateKey = require('starkbank-ecdsa').PrivateKey; +const Resource = require('../utils/resource.js').Resource +const check = require('../utils/check.js') + + +class User extends Resource { + + constructor({id, privateKey, environment}) { + super(id); + this.pem = check.key(privateKey); + this.environment = check.environment(environment); + } + + accessId() { + return this.constructor.name.toLowerCase() + '/' + this.id; + } + + privateKey() { + return PrivateKey.fromPem(this.pem); + } +} + +exports.User = User; \ No newline at end of file diff --git a/sdk/utilityPayment/index.js b/sdk/utilityPayment/index.js new file mode 100644 index 00000000..8f06ea35 --- /dev/null +++ b/sdk/utilityPayment/index.js @@ -0,0 +1,9 @@ +utilityPayment = require('./utilityPayment.js'); + +exports.log = require('./log'); +exports.create = utilityPayment.create; +exports.get = utilityPayment.get; +exports.query = utilityPayment.query; +exports.pdf = utilityPayment.pdf; +exports.delete = utilityPayment.delete; +exports.UtilityPayment = utilityPayment.UtilityPayment; \ No newline at end of file diff --git a/sdk/utilityPayment/log/index.js b/sdk/utilityPayment/log/index.js new file mode 100644 index 00000000..2d09e326 --- /dev/null +++ b/sdk/utilityPayment/log/index.js @@ -0,0 +1,4 @@ +const log = require('./log.js'); + +exports.get = log.get; +exports.query = log.query; \ No newline at end of file diff --git a/sdk/utilityPayment/log/log.js b/sdk/utilityPayment/log/log.js new file mode 100644 index 00000000..d0a25603 --- /dev/null +++ b/sdk/utilityPayment/log/log.js @@ -0,0 +1,82 @@ +const rest = require('../../utils/rest.js'); +const Resource = require('../../utils/resource.js').Resource + + +class Log extends Resource { + /** + * + * UtilityPayment Log object + * + * Every time a UtilityPayment entity is modified, a corresponding UtilityPayment Log + * is generated for the entity. This log is never generated by the user, but it can + * be retrieved to check additional information on the UtilityPayment. + * + * Attributes: + * id [string]: unique id returned when the log is created. ex: '5656565656565656' + * payment [UtilityPayment]: UtilityPayment entity to which the log refers to. + * errors [list of strings]: list of errors linked to this BoletoPayment event. + * type [string]: type of the UtilityPayment event which triggered the log creation. ex: 'registered' or 'paid' + * created [string]: creation datetime for the payment. ex: '2020-03-10 10:30:00.000' + * + */ + constructor(created, type, errors, payment, id = null) { + super(id); + this.created = created; + this.type = type; + this.errors = errors; + this.payment = payment; + } +} + +exports.Log = Log; +let resource = {'class': exports.Log, 'name': 'UtilityPaymentLog'}; + + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific UtilityPayment Log + * + * Receive a single UtilityPayment Log object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * UtilityPayment Log object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({ limit = null, after = null, before = null, types = null, paymentIds = null, user = null} = {}) { + /** + * + * Retrieve UtilityPayment Logs + * + * Receive a generator of UtilityPayment Log objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * types [list of strings, default null]: filter retrieved objects by event types. ex: 'paid' or 'registered' + * paymentIds [list of strings, default null]: list of UtilityPayment ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * list of UtilityPayment Log objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + types: types, + paymentIds: paymentIds, + }; + return rest.getList(resource, query, user); +}; diff --git a/sdk/utilityPayment/utilityPayment.js b/sdk/utilityPayment/utilityPayment.js new file mode 100644 index 00000000..8ed8320f --- /dev/null +++ b/sdk/utilityPayment/utilityPayment.js @@ -0,0 +1,163 @@ +const rest = require('../utils/rest.js'); +const check = require('../utils/check.js'); +const Resource = require('../utils/resource.js').Resource + + +class UtilityPayment extends Resource { + /** + * + * UtilityPayment object + * + * When you initialize a UtilityPayment, the entity will not be automatically + * created in the Stark Bank API. The 'create' function sends the objects + * to the Stark Bank API and returns the list of created objects. + * + * Parameters (conditionally required): + * line [string, default null]: Number sequence that describes the payment. Either 'line' or 'bar_code' parameters are required. If both are sent, they must match. ex: '34191.09008 63571.277308 71444.640008 5 81960000000062' + * barCode [string, default null]: Bar code number that describes the payment. Either 'line' or 'barCode' parameters are required. If both are sent, they must match. ex: '34195819600000000621090063571277307144464000' + * + * Parameters (required): + * description [string]: Text to be displayed in your statement (min. 10 characters). ex: 'payment ABC' + * + * Parameters (optional): + * scheduled [string, default today]: payment scheduled date. ex: '2020-03-10' + * tags [list of strings]: list of strings for tagging + * + * Attributes (return-only): + * id [string, default null]: unique id returned when payment is created. ex: '5656565656565656' + * status [string, default null]: current payment status. ex: 'registered' or 'paid' + * amount [int, default null]: amount automatically calculated from line or bar_code. ex: 23456 (= R$ 234.56) + * fee [integer, default null]: fee charged when utility payment is created. ex: 200 (= R$ 2.00) + * created [string, default null]: creation datetime for the payment. ex: '2020-03-10 10:30:00.000' + * + */ + constructor({ + description, scheduled, line, barCode, + tags, amount, status, created, + fee, id, + }) { + super(id); + this.barCode = barCode; + this.line = line; + this.description = description; + this.scheduled = check.date(scheduled); + this.tags = tags; + this.amount = amount; + this.status = status; + this.created = created; + this.status = status; + this.amount = amount; + this.fee = fee; + } +} + +exports.UtilityPayment = UtilityPayment; +let resource = {'class': exports.UtilityPayment, 'name': 'UtilityPayment'}; + + +exports.create = async function (payments, {user} = {}) { + /** + * + * Create UtilityPayments + * + * Send a list of UtilityPayment objects for creation in the Stark Bank API + * + * Parameters (required): + * payments [list of UtilityPayment objects]: list of UtilityPayment objects to be created in the API + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * Return: + * list of UtilityPayment objects with updated attributes + * + */ + return rest.post(resource, payments, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific UtilityPayment + * + * Receive a single UtilityPayment object previously created by the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + */ + return rest.getId(resource, id, user); +}; + +exports.pdf = async function (id, {user} = {}) { + /** + * + * Retrieve a specific UtilityPayment pdf file + * + * Receive a single UtilityPayment pdf file generated in the Stark Bank API by passing its id. + * Only valid for utility payments with 'success' status. + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * UtilityPayment pdf file + * + */ + return rest.getPdf(resource, id, user); +}; + +exports.query = async function ({ limit, after, before, tags, ids, status, user} = {}) { + /** + * + * Retrieve UtilityPayments + * + * Receive a generator of UtilityPayment objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * after [string, default null] date filter for objects created only after specified date. ex: '2020-03-10' + * before [string, default null] date filter for objects only before specified date. ex: '2020-03-10' + * tags [list of strings, default null]: tags to filter retrieved objects. ex: ['tony', 'stark'] + * ids [list of strings, default null]: list of ids to filter retrieved objects. ex: ['5656565656565656', '4545454545454545'] + * status [string, default null]: filter for status of retrieved objects. ex: 'paid' + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of UtilityPayment objects with updated attributes + * + */ + let query = { + limit: limit, + after: after, + before: before, + tags: tags, + ids: ids, + status: status, + }; + return rest.getList(resource, query, user); +}; + +exports.delete = async function (id, {user} = {}) { + /** + * + * Delete a UtilityPayment entity + * + * Delete a UtilityPayment entity previously created in the Stark Bank API + * + * Parameters (required): + * id [string]: UtilityPayment unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * deleted UtilityPayment with updated attributes + * + */ + return rest.deleteId(resource, id, user); +}; \ No newline at end of file diff --git a/sdk/utils/api.js b/sdk/utils/api.js new file mode 100644 index 00000000..be02156b --- /dev/null +++ b/sdk/utils/api.js @@ -0,0 +1,19 @@ +const decamelize = require('decamelize'); + + +exports.endpoint = function (resource, keepDash = false) { + let decamelized = decamelize(resource, '-'); + if (keepDash) { + return decamelized; + } + return decamelized.replace('-log', '/log'); +}; + +exports.lastName = function (resource) { + let splitString = decamelize(resource, '-').split('-'); + return splitString[splitString.length - 1]; +}; + +exports.lastPlural = function (resource) { + return `${exports.lastName(resource, true)}s`; +}; \ No newline at end of file diff --git a/sdk/utils/check.js b/sdk/utils/check.js new file mode 100644 index 00000000..683fad5e --- /dev/null +++ b/sdk/utils/check.js @@ -0,0 +1,42 @@ +const PrivateKey = require('starkbank-ecdsa').PrivateKey; + + +function formatDate(date) { + let d = new Date(date), + month = '' + (d.getMonth() + 1), + day = '' + d.getDate(), + year = d.getFullYear(); + + if (month.length < 2) + month = '0' + month; + if (day.length < 2) + day = '0' + day; + + return [year, month, day].join('-'); +} + +exports.date = function (input) { + if (typeof input === 'string') { + return input; + } + let date = new Date(input); + + return formatDate(date); +}; + +exports.key = function (key) { + try { + PrivateKey.fromPem(key); + } catch (e) { + throw new Error('Invalid private key, try another one'); + } + return key; +}; + +exports.environment = function (environment) { + let validEnvironments = ['production', 'sandbox']; + if (validEnvironments.includes(environment)){ + return environment; + } + throw Error(`Invalid environment, please choose among ${validEnvironments}`); +}; \ No newline at end of file diff --git a/sdk/utils/request.js b/sdk/utils/request.js new file mode 100644 index 00000000..69641168 --- /dev/null +++ b/sdk/utils/request.js @@ -0,0 +1,160 @@ +const starkbank = require('../../index.js'); +const Ecdsa = require('starkbank-ecdsa').Ecdsa; +const pjson = require('../../package.json'); +const error = require('../error.js'); +const got = require('got'); + + +class Response { + + constructor(status, content) { + this.status = status; + this.content = content; + } + + json() { + return JSON.parse(self.content); + } +} + +exports.fetch = async function (path, method = 'GET', payload = null, query = null, user = null, version = 'v2') { + user = user || starkbank.user; + + if (!user) { + throw Error('A user is required to access our API. Check our docs: https://github.com/starkbank/sdk-node/'); + } + + let hostname = { + 'production': 'https://api.starkbank.com/' + version, + 'sandbox': 'https://sandbox.api.starkbank.com/' + version + }[user.environment]; + + let options = { + method: method, + }; + + let url = hostname + path; + if (query) { + let queryString = ''; + let separator = '?'; + for (let key in query) { + if (query[key]) { + queryString += separator + key + '=' + query[key]; + separator = '&'; + } + } + url += queryString; + } + let accessTime = Math.round((new Date()).getTime() / 1000); + let message = user.accessId() + ':' + accessTime + ':'; + + if (payload && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { + let body = JSON.stringify(payload); + message += body; + options['body'] = body; + } + + options['headers'] = { + 'Access-Id': user.accessId(), + 'Access-Time': accessTime, + 'Access-Signature': Ecdsa.sign(message, user.privateKey()).toBase64(), + 'User-Agent': 'Node-' + process.versions['node'] + '-SDK-' + pjson.version, + 'Content-Type': 'application/json' + }; + let response; + let content; + let status; + try { + response = await got(url, options); + content = response.body; + status = response.statusCode; + } catch (e) { + if (!e.response) { + throw e; + } + content = e.response.body; + status = e.response.statusCode; + switch (status) { + case 400: + case 404: + throw new error.InputErrors(content, status); + case 500: + throw new error.InternalServerError(content, status); + default: + throw e; + } + } + return new Response(status, content); +}; + +exports.fetchBuffer = async function (path, method = 'GET', payload = null, query = null, user = null, version = 'v2') { + user = user || starkbank.user; + + if (!user) { + throw Error('A user is required to access our API. Check our docs: https://github.com/starkbank/sdk-node/'); + } + + let hostname = { + 'production': 'https://api.starkbank.com/' + version, + 'sandbox': 'https://sandbox.api.starkbank.com/' + version + }[user.environment]; + + let options = { + method: method, + }; + + let url = hostname + path; + if (query) { + let queryString = ''; + let separator = '?'; + for (let key in query) { + if (query[key]) { + queryString += separator + key + '=' + query[key]; + separator = '&'; + } + } + url += queryString; + } + let accessTime = Math.round((new Date()).getTime() / 1000); + let message = user.accessId() + ':' + accessTime + ':'; + + if (payload && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { + let body = JSON.stringify(payload); + message += body; + options['body'] = body; + } + options['responseType'] = 'buffer'; + options['headers'] = { + 'Access-Id': user.accessId(), + 'Access-Time': accessTime, + 'Access-Signature': Ecdsa.sign(message, user.privateKey()).toBase64(), + 'User-Agent': 'Node-' + process.versions['node'] + '-SDK-' + pjson.version, + 'Content-Type': 'application/json' + }; + let response; + let content; + let status; + try { + const responsePromise = got(url, options); + const bufferPromise = responsePromise.buffer(); + content = await bufferPromise; + status = 200; + } catch (e) { + if (!e.response) { + throw e; + } + content = e.response.body; + status = e.response.statusCode; + switch (status) { + case 400: + case 404: + throw new error.InputErrors(content, status); + case 500: + throw new error.InternalServerError(content, status); + default: + throw e; + } + } + return new Response(status, content); +}; + diff --git a/sdk/utils/resource.js b/sdk/utils/resource.js new file mode 100644 index 00000000..4e3e42eb --- /dev/null +++ b/sdk/utils/resource.js @@ -0,0 +1,10 @@ + + +class Resource { + + constructor(id) { + this.id = id ? id.toString() : null; + } +} + +exports.Resource = Resource; \ No newline at end of file diff --git a/sdk/utils/rest.js b/sdk/utils/rest.js new file mode 100644 index 00000000..37d2c22d --- /dev/null +++ b/sdk/utils/rest.js @@ -0,0 +1,109 @@ +const api = require('./api.js'); +const fetch = require('./request').fetch; +const fetchBuffer = require('./request').fetchBuffer; + + +exports.getList = async function* (resource, query, user = null) { + let json; + let response; + let list; + let cursor = ''; + let limit = query['limit'] ? query['limit'] : null; + let entity = new resource['class']({}); + let names = api.lastPlural(entity.constructor.name); + let endpoint = `${api.endpoint(resource['name'])}`; + do { + if (!query) { + query = {}; + } else { + for (let key in query) { + if (Array.isArray(query[key])) { + query[key] = query[key].join(); + } + } + } + Object.assign(query, { + 'limit': Math.min(100, limit), + 'cursor': cursor, + }); + response = await fetch(`/${endpoint}`, method = 'GET', null, query, user, 'v2'); + json = JSON.parse(response.content); + list = json[api.lastName(names)]; + cursor = json['cursor']; + if (limit) { + limit -= 100; + } + for (let entity of list) { + yield Object.assign(new resource['class'](entity), entity); + } + } while (cursor && (limit === null || limit > 0)); +}; + +exports.post = async function (resource, entities, user = null) { + let entity = new resource['class']({}); + let names = api.lastPlural(entity.constructor.name); + let endpoint = `${api.endpoint(resource['name'])}`; + for (let entity of entities) { + Object.keys(entity).forEach(key => entity[key] === null && delete entity[key]); + } + let payload = {}; + payload[names] = entities; + let response = await fetch(`/${endpoint}`, 'POST', payload, null, user); + let list = JSON.parse(response.content)[api.lastName(names)]; + let newList = []; + for (let entity of list) { + let newResource = new resource['class'](entity); + newList.push(Object.assign(newResource, entity)); + } + return newList; +}; + +exports.getPdf = async function (resource, id, user = null) { + let entity = new resource['class']({}); + let name = entity.constructor.name; + let endpoint = `${api.endpoint(resource['name'])}/${id}/pdf`; + let response = await fetchBuffer(`/${endpoint}`, 'GET', null, null, user); + return response.content; +}; + +exports.getId = async function (resource, id, user = null, callback) { + let entity = new resource['class']({}); + let name = entity.constructor.name; + let endpoint = `${api.endpoint(resource['name'])}/${id}`; + let response = await fetch(`/${endpoint}`, 'GET', null, null, user); + let returnEntity = JSON.parse(response.content)[api.lastName(name)]; + return Object.assign(new resource['class'](returnEntity), returnEntity); +}; + +exports.getPublicKey = async function (user) { + let response = await fetch(path = '/public-key', 'GET', null, {'limit': 1}, user); + return JSON.parse(response.content)['publicKeys'][0]['content']; +}; + +exports.deleteId = async function (resource, id, user = null) { + let entity = new resource['class']({}); + let name = entity.constructor.name; + let endpoint = `${api.endpoint(resource['name'])}/${id}`; + let response = await fetch(`/${endpoint}`, 'DELETE', null, null, user); + let returnEntity = JSON.parse(response.content)[api.lastName(name)]; + return Object.assign(new resource['class'](returnEntity), returnEntity); +}; + +exports.postSingle = async function (resource, options, user = null) { + let entity = new resource['class']({}); + let name = api.lastName(entity.constructor.name); + let endpoint = `${api.endpoint(resource['name'])}`; + let payload = Object.assign(entity, options); + let response = await fetch(`/${endpoint}`, 'POST', payload, null, user); + let returnEntity = JSON.parse(response.content)[name]; + return Object.assign(new resource['class'](returnEntity), returnEntity); +}; + +exports.patchId = async function (resource, id, payload, user = null) { + let entity = new resource['class']({}); + let name = entity.constructor.name; + let endpoint = `${api.endpoint(resource['name'])}/${id}`; + let response = await fetch(`/${endpoint}`, 'PATCH', payload, null, user); + let returnEntity = JSON.parse(response.content)[api.lastName(name)]; + return Object.assign(new resource['class'](returnEntity), returnEntity); +}; \ No newline at end of file diff --git a/sdk/webhook/index.js b/sdk/webhook/index.js new file mode 100644 index 00000000..246052d4 --- /dev/null +++ b/sdk/webhook/index.js @@ -0,0 +1,7 @@ +const webhook = require('./webhook.js'); + +exports.create = webhook.create; +exports.delete = webhook.delete; +exports.query = webhook.query; +exports.get = webhook.get; +exports.Webhook = webhook.Webhook; diff --git a/sdk/webhook/webhook.js b/sdk/webhook/webhook.js new file mode 100644 index 00000000..21213f8b --- /dev/null +++ b/sdk/webhook/webhook.js @@ -0,0 +1,115 @@ +const rest = require('../utils/rest.js'); +const Resource = require('../utils/resource.js').Resource + + +class Webhook extends Resource { + /** + * + * Webhook subscription object + * + * A Webhook is used to subscribe to notification events on a user-selected endpoint. + * Currently available services for subscription are transfer, boleto, boleto-payment, + * and utility-payment + * + * Parameters (required): + * url [string]: Url that will be notified when an event occurs. + * subscriptions [list of strings]: list of any non-empty combination of the available services. ex: ['transfer', 'boleto-payment'] + * Attributes: + * id [string, default null]: unique id returned when the log is created. ex: '5656565656565656' + * + */ + constructor({url, subscriptions, id = null}) { + super(id); + this.url = url; + this.subscriptions = subscriptions; + } +} + +exports.Webhook = Webhook; +let resource = {'class': exports.Webhook, 'name': 'Webhook'}; + +exports.create = async function ({url, subscriptions, user = null} = {}) { + /** + * + * Create Webhook subscription + * + * Send a single Webhook subscription for creation in the Stark Bank API + * + * Parameters (required): + * url [string]: url to which notification events will be sent to. ex: 'https://webhook.site/60e9c18e-4b5c-4369-bda1-ab5fcd8e1b29' + * subscriptions [list of strings]: list of any non-empty combination of the available services. ex: ['transfer', 'boleto-payment'] + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Webhook object with updated attributes + * + */ + let options = { + url: url, + subscriptions: subscriptions, + }; + return rest.postSingle(resource, options, user); +}; + +exports.get = async function (id, {user} = {}) { + /** + * + * Retrieve a specific Webhook subscription + * + * Receive a single Webhook subscription object previously created in the Stark Bank API by passing its id + * + * Parameters (required): + * id [string]: object unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * Webhook object with updated attributes + * + */ + return rest.getId(resource, id, user); +}; + +exports.query = async function ({limit = null, user = null} = {}) { + /** + * + * Retrieve Webhook subcriptions + * + * Receive a generator of Webhook subcription objects previously created in the Stark Bank API + * + * Parameters (optional): + * limit [integer, default null]: maximum number of objects to be retrieved. Unlimited if null. ex: 35 + * user [Project object, default null]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * generator of Webhook objects with updated attributes + * + */ + let query = { + limit: limit, + }; + return rest.getList(resource, query, user); +}; + +exports.delete = async function (id, {user} = {}) { + /** + * + * Delete a Webhook subscription entity + * + * Delete a Webhook subscription entity previously created in the Stark Bank API + * + * Parameters (required): + * id [string]: Webhook unique id. ex: '5656565656565656' + * + * Parameters (optional): + * user [Project object]: Project object. Not necessary if starkbank.user was set before function call + * + * Return: + * deleted Webhook with updated attributes + * + */ + return rest.deleteId(resource, id, user); +}; \ No newline at end of file diff --git a/tests/testBalance.js b/tests/testBalance.js new file mode 100644 index 00000000..f5468e82 --- /dev/null +++ b/tests/testBalance.js @@ -0,0 +1,12 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestBalanceGet', () => { + it('test_success', async () => { + let balance = await starkbank.balance.get(); + assert(typeof balance.amount == 'number'); + }); +}); diff --git a/tests/testBoleto.js b/tests/testBoleto.js new file mode 100644 index 00000000..25eb648c --- /dev/null +++ b/tests/testBoleto.js @@ -0,0 +1,61 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleBoletosJson = require('./utils/boleto.js').generateExampleBoletosJson; + +starkbank.user = require('./utils/user').exampleProject; + +describe('TestBoletoPost', () => { + it('test_success', async () => { + let boletos = generateExampleBoletosJson(5); + boletos = await starkbank.boleto.create(boletos); + for (let boleto of boletos) { + assert(typeof boleto.id == 'string'); + } + }); +}); + +describe('TestBoletoGet', () => { + it('test_success', async () => { + let i = 0; + const boletos = await starkbank.boleto.query({limit: 150}); + for await (let boleto of boletos) { + assert(typeof boleto.id == 'string'); + i += 1; + } + assert(i === 150); + console.log('Number of boletos:', i); + }); +}); + +describe('TestBoletoPostAndDelete', () => { + it('test_success', async () => { + let boletos = generateExampleBoletosJson(1); + boletos = await starkbank.boleto.create(boletos); + let boleto = boletos[0]; + assert(typeof boleto.id == 'string'); + boleto = await starkbank.boleto.delete(boleto.id); + assert(typeof boleto.id == 'string'); + }); +}); + +describe('TestBoletoInfoGet', () => { + it('test_success', async () => { + let boletos = await starkbank.boleto.query({limit: 1}); + for await (let boleto of boletos) { + assert(typeof boleto.id == 'string'); + boleto = await starkbank.boleto.get(boleto.id); + assert(typeof boleto.id == 'string'); + } + }); +}); + +describe('TestBoletoPdfGet', () => { + it('test_success', async () => { + let boletos = await starkbank.boleto.query({limit: 1}); + for await (let boleto of boletos) { + assert(typeof boleto.id == 'string'); + let pdf = await starkbank.boleto.pdf(boleto.id); + assert(Buffer.isBuffer(pdf)); + } + }); +}); diff --git a/tests/testBoletoLog.js b/tests/testBoletoLog.js new file mode 100644 index 00000000..88e2bca6 --- /dev/null +++ b/tests/testBoletoLog.js @@ -0,0 +1,30 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestBoletoLogGet', () => { + it('test_success', async () => { + let i = 0; + const logs = await starkbank.boleto.log.query({limit: 150}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + i += 1; + } + assert(i === 150); + console.log('Number of logs:', i); + }); +}); + + +describe('TestBoletoLogInfoGet', () => { + it('test_success', async () => { + let logs = await starkbank.boleto.log.query({limit: 1}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + log = await starkbank.boleto.log.get(log.id); + assert(typeof log.id == 'string'); + } + }); +}); diff --git a/tests/testBoletoPayment.js b/tests/testBoletoPayment.js new file mode 100644 index 00000000..3ccb5456 --- /dev/null +++ b/tests/testBoletoPayment.js @@ -0,0 +1,62 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleBoletoPaymentsJson = require('./utils/boletoPayment.js').generateExampleBoletoPaymentsJson; + +starkbank.user = require('./utils/user').exampleProject; + +describe('TestBoletoPaymentPost', () => { + it('test_success', async () => { + let payments = await generateExampleBoletoPaymentsJson(5); + payments = await starkbank.boletoPayment.create(payments); + for (let payment of payments) { + assert(typeof payment.id == 'string'); + } + }); +}); + +describe('TestBoletoPaymentGet', () => { + it('test_success', async () => { + let i = 0; + const payments = await starkbank.boletoPayment.query({limit: 5}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + i += 1; + } + console.log(i); + assert(i === 5); + console.log('Number of boletos:', i); + }); +}); + +describe('TestBoletoPaymentPostAndDelete', () => { + it('test_success', async () => { + let payments = await generateExampleBoletoPaymentsJson(1); + payments = await starkbank.boletoPayment.create(payments); + let payment = payments[0]; + assert(typeof payment.id == 'string'); + payment = await starkbank.boletoPayment.delete(payment.id); + assert(typeof payment.id == 'string'); + }); +}); + +describe('TestBoletoPaymentInfoGet', () => { + it('test_success', async () => { + let payments = await starkbank.boletoPayment.query({limit: 1}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + payment = await starkbank.boletoPayment.get(payment.id); + assert(typeof payment.id == 'string'); + } + }); +}); + +describe('TestBoletoPaymentPdfGet', () => { + it('test_success', async () => { + let payments = await starkbank.boletoPayment.query({limit: 1, status: ['processing']}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + let pdf = await starkbank.boletoPayment.pdf(payment.id); + assert(Buffer.isBuffer(pdf)); + } + }); +}); diff --git a/tests/testBoletoPaymentLog.js b/tests/testBoletoPaymentLog.js new file mode 100644 index 00000000..91c57a4f --- /dev/null +++ b/tests/testBoletoPaymentLog.js @@ -0,0 +1,83 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const { futureDate } = require('./utils/random') + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestBoletoPaymentLogGet', () => { + it('test_success', async () => { + let i = 0; + const logs = await starkbank.boletoPayment.log.query({limit: 5}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + i += 1; + } + assert(i === 5); + console.log('Number of logs:', i); + }); + + it('works with paymentIds', async () => { + const makeBoleto = (name, amount) => ({ + amount: amount, + name: name, + taxId: '012.345.678-90', + streetLine1: 'Av. Paulista, 200', + streetLine2: '10 andar', + district: 'Bela Vista', + city: 'São Paulo', + stateCode: 'SP', + zipCode: '01310-000', + }) + + let [boleto1, boleto2] = await starkbank.boleto.create([ + makeBoleto("Fulano de Tal", 10000), + makeBoleto("Beltrano da Silta", 10000), + ]) + + const tomorrow = futureDate(1) + + let [payment1, payment2] = await starkbank.boletoPayment.create([ + { + taxId: boleto1.taxId, + description: `Payment to ${boleto1.name}`, + scheduled: tomorrow, + line: boleto1.line, + }, + { + taxId: boleto2.taxId, + description: `Payment to ${boleto2.name}`, + scheduled: tomorrow, + line: boleto2.line, + } + ]); + + let paymentLogs = await starkbank.boletoPayment.log.query({ + paymentIds: [payment1.id] + }); + + for await (let log of paymentLogs) { + assert(log.payment.id == payment1.id) + } + + let paymentLogs2 = await starkbank.boletoPayment.log.query({ + paymentIds: [payment2.id] + }); + + for await (let log of paymentLogs2) { + assert(log.payment.id == payment2.id) + } + }); +}); + + +describe('TestBoletoPaymentLogInfoGet', () => { + it('test_success', async () => { + let logs = await starkbank.boletoPayment.log.query({limit: 1}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + log = await starkbank.boletoPayment.log.get(log.id); + assert(typeof log.id == 'string'); + } + }); +}); diff --git a/tests/testEvent.js b/tests/testEvent.js new file mode 100644 index 00000000..13e9442a --- /dev/null +++ b/tests/testEvent.js @@ -0,0 +1,76 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestEventGet', () => { + it('test_success', async () => { + let i = 0; + const events = await starkbank.event.query({limit: 5}); + for await (let event of events) { + assert(typeof event.id == 'string'); + i += 1; + } + console.log('Number of events:', i); + }); +}); + + +describe('TestEventInfoGet', () => { + it('test_success', async () => { + let events = await starkbank.event.query({limit: 1}); + for await (let event of events) { + assert(typeof event.id == 'string'); + event = await starkbank.event.get(event.id); + assert(typeof event.id == 'string'); + } + }); +}); + +describe('TestEventParse', () => { + it('test_success', async () => { + content = '{"event": {"log": {"transfer": {"status": "processing", "updated": "2020-04-03T13:20:33.485644+00:00", "fee": 160, "name": "Lawrence James", "accountNumber": "10000-0", "id": "5107489032896512", "tags": [], "taxId": "91.642.017/0001-06", "created": "2020-04-03T13:20:32.530367+00:00", "amount": 2, "transactionIds": ["6547649079541760"], "bankCode": "01", "branchCode": "0001"}, "errors": [], "type": "sending", "id": "5648419829841920", "created": "2020-04-03T13:20:33.164373+00:00"}, "subscription": "transfer", "id": "6234355449987072", "created": "2020-04-03T13:20:40.784479+00:00"}}'; + valid_signature = 'MEYCIQCmFCAn2Z+6qEHmf8paI08Ee5ZJ9+KvLWSS3ddp8+RF3AIhALlK7ltfRvMCXhjS7cy8SPlcSlpQtjBxmhN6ClFC0Tv6'; + + let event = await starkbank.event.parse({ + content: content, + signature: valid_signature + }); + console.log(event); + }); + + it('test_invalid_signature', async () => { + content = '{"event": {"log": {"transfer": {"status": "processing", "updated": "2020-04-03T13:20:33.485644+00:00", "fee": 160, "name": "Lawrence James", "accountNumber": "10000-0", "id": "5107489032896512", "tags": [], "taxId": "91.642.017/0001-06", "created": "2020-04-03T13:20:32.530367+00:00", "amount": 2, "transactionIds": ["6547649079541760"], "bankCode": "01", "branchCode": "0001"}, "errors": [], "type": "sending", "id": "5648419829841920", "created": "2020-04-03T13:20:33.164373+00:00"}, "subscription": "transfer", "id": "6234355449987072", "created": "2020-04-03T13:20:40.784479+00:00"}}'; + invalid_signature = 'MEYCIQCmFCAn2Z+6qEHmf8paI08Ee5ZJ9+KvLWSS3ddp8+RF3AIhALlK7ltfRvMCXhjS7cy8SPlcSlpQtjBxmhN6ClFC0Tv5'; + + try { + await starkbank.event.parse({ + content: content, + signature: invalid_signature + }); + throw new Error('Oops, signature was accepted!'); + } catch (e) { + if (e instanceof starkbank.error.InvalidSignatureError) + console.log('Correctly rejected signature'); + else throw e; + } + }); + + it('test_malformed_signature', async () => { + content = '{"event": {"log": {"transfer": {"status": "processing", "updated": "2020-04-03T13:20:33.485644+00:00", "fee": 160, "name": "Lawrence James", "accountNumber": "10000-0", "id": "5107489032896512", "tags": [], "taxId": "91.642.017/0001-06", "created": "2020-04-03T13:20:32.530367+00:00", "amount": 2, "transactionIds": ["6547649079541760"], "bankCode": "01", "branchCode": "0001"}, "errors": [], "type": "sending", "id": "5648419829841920", "created": "2020-04-03T13:20:33.164373+00:00"}, "subscription": "transfer", "id": "6234355449987072", "created": "2020-04-03T13:20:40.784479+00:00"}}'; + malformed_signature = 'something is definitely wrong'; + + try { + await starkbank.event.parse({ + content: content, + signature: malformed_signature + }); + throw new Error('Oops, signature was accepted!'); + } catch (e) { + if (e instanceof starkbank.error.InvalidSignatureError) + console.log('Correctly rejected signature'); + else throw e; + } + }); +}); diff --git a/tests/testTransaction.js b/tests/testTransaction.js new file mode 100644 index 00000000..1f6a16af --- /dev/null +++ b/tests/testTransaction.js @@ -0,0 +1,39 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleTransactionsJson = require('./utils/transaction.js').generateExampleTransactionsJson; + +starkbank.user = require('./utils/user').exampleProject; + +describe('TestTransactionPost', () => { + it('test_success', async () => { + let transfers = generateExampleTransactionsJson(1); + transfers = await starkbank.transaction.create(transfers); + for (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + } + }); +}); + +describe('TestTransactionGet', () => { + it('test_success', async () => { + let i = 0; + const transfers = await starkbank.transaction.query({limit: 150}); + for await (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + i += 1; + } + assert(i === 150); + console.log('Number of Transactions:', i); + }); +}); + +describe('TestTransactionInfoGet', () => { + it('test_success', async () => { + let transfers = await starkbank.transaction.query({limit: 1}); + for await (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + transfer = await starkbank.transaction.get(transfer.id); + assert(typeof transfer.id == 'string'); + } + }); +}); diff --git a/tests/testTransfer.js b/tests/testTransfer.js new file mode 100644 index 00000000..8a40c14f --- /dev/null +++ b/tests/testTransfer.js @@ -0,0 +1,50 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleTransfersJson = require('./utils/transfer.js').generateExampleTransfersJson; + +starkbank.user = require('./utils/user').exampleProject; + +describe('TestTransferPost', () => { + it('test_success', async () => { + let transfers = generateExampleTransfersJson(5); + transfers = await starkbank.transfer.create(transfers); + for (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + } + }); +}); + +describe('TestTransferGet', () => { + it('test_success', async () => { + let i = 0; + const transfers = await starkbank.transfer.query({limit: 150}); + for await (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + i += 1; + } + assert(i === 150); + console.log('Number of boletos:', i); + }); +}); + +describe('TestTransferInfoGet', () => { + it('test_success', async () => { + let transfers = await starkbank.transfer.query({limit: 1}); + for await (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + transfer = await starkbank.transfer.get(transfer.id); + assert(typeof transfer.id == 'string'); + } + }); +}); + +describe('TestTransferPdfGet', () => { + it('test_success', async () => { + let transfers = await starkbank.transfer.query({limit: 1, status: 'processing'}); + for await (let transfer of transfers) { + assert(typeof transfer.id == 'string'); + let pdf = await starkbank.transfer.pdf(transfer.id); + assert(Buffer.isBuffer(pdf)); + } + }); +}); diff --git a/tests/testTransferLog.js b/tests/testTransferLog.js new file mode 100644 index 00000000..54617e7d --- /dev/null +++ b/tests/testTransferLog.js @@ -0,0 +1,31 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestTransferLogGet', () => { + it('test_success', async () => { + let i = 0; + const logs = await starkbank.transfer.log.query({limit: 5}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + i += 1; + } + console.log(i) + assert(i === 5); + console.log('Number of logs:', i); + }); +}); + + +describe('TestTransferLogInfoGet', () => { + it('test_success', async () => { + let logs = await starkbank.transfer.log.query({limit: 1}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + log = await starkbank.transfer.log.get(log.id); + assert(typeof log.id == 'string'); + } + }); +}); diff --git a/tests/testUtilityPayment.js b/tests/testUtilityPayment.js new file mode 100644 index 00000000..02ca919b --- /dev/null +++ b/tests/testUtilityPayment.js @@ -0,0 +1,62 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleUtilityPaymentsJson = require('./utils/utilityPayment.js').generateExampleUtilityPaymentsJson; + +starkbank.user = require('./utils/user').exampleProject; + +describe('TestUtilityPaymentPost', () => { + it('test_success', async () => { + let payments = await generateExampleUtilityPaymentsJson(5); + payments = await starkbank.utilityPayment.create(payments); + for (let payment of payments) { + assert(typeof payment.id == 'string'); + } + }); +}); + +describe('TestUtilityPaymentGet', () => { + it('test_success', async () => { + let i = 0; + const payments = await starkbank.utilityPayment.query({limit: 5}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + i += 1; + } + console.log(i) + assert(i === 5); + console.log('Number of boletos:', i); + }); +}); + +describe('TestUtilityPaymentPostAndDelete', () => { + it('test_success', async () => { + let payments = await generateExampleUtilityPaymentsJson(1); + payments = await starkbank.utilityPayment.create(payments); + let payment = payments[0]; + assert(typeof payment.id == 'string'); + payment = await starkbank.utilityPayment.delete(payment.id); + assert(typeof payment.id == 'string'); + }); +}); + +describe('TestUtilityPaymentInfoGet', () => { + it('test_success', async () => { + let payments = await starkbank.utilityPayment.query({limit: 1}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + payment = await starkbank.utilityPayment.get(payment.id); + assert(typeof payment.id == 'string'); + } + }); +}); + +describe('TestUtilityPaymentPdfGet', () => { + it('test_success', async () => { + let payments = await starkbank.utilityPayment.query({limit: 1, status: 'processing'}); + for await (let payment of payments) { + assert(typeof payment.id == 'string'); + let pdf = await starkbank.utilityPayment.pdf(payment.id); + assert(Buffer.isBuffer(pdf)); + } + }); +}); diff --git a/tests/testUtilityPaymentLog.js b/tests/testUtilityPaymentLog.js new file mode 100644 index 00000000..c8d04483 --- /dev/null +++ b/tests/testUtilityPaymentLog.js @@ -0,0 +1,31 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestUtilityPaymentLogGet', () => { + it('test_success', async () => { + let i = 0; + const logs = await starkbank.utilityPayment.log.query({limit: 5}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + i += 1; + } + console.log(i) + assert(i === 5); + console.log('Number of logs:', i); + }); +}); + + +describe('TestUtilityPaymentLogInfoGet', () => { + it('test_success', async () => { + let logs = await starkbank.utilityPayment.log.query({limit: 1}); + for await (let log of logs) { + assert(typeof log.id == 'string'); + log = await starkbank.utilityPayment.log.get(log.id); + assert(typeof log.id == 'string'); + } + }); +}); diff --git a/tests/testWebhook.js b/tests/testWebhook.js new file mode 100644 index 00000000..02a1917f --- /dev/null +++ b/tests/testWebhook.js @@ -0,0 +1,39 @@ +const assert = require('assert'); +const starkbank = require('../index.js'); +const generateExampleWebhook = require('./utils/webhook').generateExampleWebhook; + +starkbank.user = require('./utils/user').exampleProject; + + +describe('TestWebhookGet', () => { + it('test_success', async () => { + let i = 0; + const webhooks = await starkbank.webhook.query({limit: 5}); + for await (let webhook of webhooks) { + assert(typeof webhook.id == 'string'); + i += 1; + } + console.log('Number of webhooks:', i); + }); +}); + +describe('TestWebhookPostAndDelete', () => { + it('test_success', async () => { + let webhook = generateExampleWebhook(1); + webhook = await starkbank.webhook.create({url: webhook.url, subscriptions: webhook.subscriptions}); + assert(typeof webhook.id == 'string'); + webhook = await starkbank.webhook.delete(webhook.id); + assert(typeof webhook.id == 'string'); + }); +}); + +describe('TestWebhookInfoGet', () => { + it('test_success', async () => { + let webhooks = await starkbank.webhook.query({limit: 1}); + for await (let webhook of webhooks) { + assert(typeof webhook.id == 'string'); + webhook = await starkbank.webhook.get(webhook.id); + assert(typeof webhook.id == 'string'); + } + }); +}); \ No newline at end of file diff --git a/tests/utils/boleto.js b/tests/utils/boleto.js new file mode 100644 index 00000000..b55e7933 --- /dev/null +++ b/tests/utils/boleto.js @@ -0,0 +1,56 @@ +const starkbank = require('../../index.js'); +const random = require('./random.js'); + +var defaultExampleBoleto = new starkbank.Boleto({ + amount: 10, + name: 'Random Company', + taxId: '012.345.678-90', + streetLine1: 'Rua ABC', + streetLine2: 'Ap 123', + district: 'Copacabana', + city: 'Rio de Janeiro', + stateCode: 'SP', + zipCode: '01234-567', + due: '2020-03-29', + fine: 0.00, + interest: 0.00, + overdueLimit: 59, + tags: null, + descriptions: [ + { + 'text': 'product A', + 'amount': 123 + }, + { + 'text': + 'product B', + 'amount': + 456 + } + , + { + 'text': + 'product C', + 'amount': + 789 + } + ] +}); + + +exports.generateExampleBoletosJson = function (n, amount = null) { + let boletos = []; + let exampleBoleto = JSON.parse(JSON.stringify(defaultExampleBoleto)); + for (let i = 0; i < n; i++) { + let boletoAmount = Math.floor(amount); + if (!amount) { + boletoAmount = random.randomInt(200, 1000); + } + exampleBoleto.name = 'Jon Snow'; + exampleBoleto.amount = boletoAmount; + exampleBoleto.due = random.futureDate(7); + exampleBoleto.taxId = '012.345.678-90'; + boletos.push(new starkbank.Boleto(JSON.parse(JSON.stringify(exampleBoleto)))); + } + return boletos; +}; diff --git a/tests/utils/boletoPayment.js b/tests/utils/boletoPayment.js new file mode 100644 index 00000000..cb7207a6 --- /dev/null +++ b/tests/utils/boletoPayment.js @@ -0,0 +1,35 @@ +const starkbank = require('../../index.js'); +const random = require('./random.js'); +const check = require('../../sdk/utils/check.js'); +const generateExampleBoletosJson = require('./boleto').generateExampleBoletosJson; + +starkbank.user = require('../utils/user').exampleProject; + +var defaultExampleBoletoPayment = new starkbank.BoletoPayment({ + taxId: '20.018.183/0001-80', + line: '34191.09008 61713.957308 71444.640008 2 83430000984732', + scheduled: '2020-02-29', + description: 'loading a random account', +}); + + +exports.generateExampleBoletoPaymentsJson = async function (n) { + let boletos = generateExampleBoletosJson(n); + let lines = []; + let amounts = []; + boletos = await starkbank.boleto.create(boletos); + for (let i = 0; i < n; i++) { + lines.push(boletos[i].line); + amounts.push(boletos[i].amount); + } + + let payments = []; + let exampleBoletoPayment = JSON.parse(JSON.stringify(defaultExampleBoletoPayment)); + for (let i = 0; i < n; i++) { + exampleBoletoPayment.line = lines[i]; + exampleBoletoPayment.description = `Pagamento ${amounts[i]}`; + exampleBoletoPayment.scheduled = check.date(random.futureDate(7)); + payments.push(new starkbank.BoletoPayment(JSON.parse(JSON.stringify(exampleBoletoPayment)))); + } + return payments; +}; diff --git a/tests/utils/random.js b/tests/utils/random.js new file mode 100644 index 00000000..7dc063ea --- /dev/null +++ b/tests/utils/random.js @@ -0,0 +1,11 @@ +exports.randomInt = function (min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +}; + +exports.futureDate = function (number) { + let date = new Date(); + date.setDate(date.getDate() + number); + return date.toISOString().substring(0, 10); +}; diff --git a/tests/utils/transaction.js b/tests/utils/transaction.js new file mode 100644 index 00000000..d1903749 --- /dev/null +++ b/tests/utils/transaction.js @@ -0,0 +1,26 @@ +const random = require('./random'); +const starkbank = require('../../index.js'); + +defaultExampleTransaction = new starkbank.Transaction({ + amount: 50, + receiverId: '12345', + externalId: 'unique identifier', + description: 'Transferencia para Workspace aleatorio' + }, +); + + +exports.generateExampleTransactionsJson = function (n = 1) { + + let transactions = []; + let exampleTransaction = JSON.parse(JSON.stringify(defaultExampleTransaction)); + for (let i = 0; i < n; i++) { + let transactionAmount = random.randomInt(1, 10); + exampleTransaction.receiverId = '5768064935133184'; + exampleTransaction.amount = transactionAmount; + exampleTransaction.externalId = 'Test ' + Date(); + transactions.push(Object.assign(new starkbank.Transfer({}), JSON.parse(JSON.stringify(exampleTransaction)))); + } + return transactions; + +}; \ No newline at end of file diff --git a/tests/utils/transfer.js b/tests/utils/transfer.js new file mode 100644 index 00000000..8c784a49 --- /dev/null +++ b/tests/utils/transfer.js @@ -0,0 +1,27 @@ +const starkbank = require('../../index.js'); +const random = require('./random.js'); + +var defaultExampleTransfer = new starkbank.Transfer({ + amount: 10, + name: 'João da Silva', + taxId: '01234567890', + bankCode: '01', + branchCode: '0001', + accountNumber: '10000-0', +}); + +exports.generateExampleTransfersJson = function (n, amount = null) { + let transfers = []; + let exampleTransfer = JSON.parse(JSON.stringify(defaultExampleTransfer)); + for (let i = 0; i < n; i++) { + let transferAmount = Math.floor(amount); + if (!amount) { + transferAmount = random.randomInt(5, 1000); + } + exampleTransfer.name = 'Jon Snow'; + exampleTransfer.amount = transferAmount; + exampleTransfer.taxId = '012.345.678-90'; + transfers.push(Object.assign(new starkbank.Transfer({}), JSON.parse(JSON.stringify(exampleTransfer)))); + } + return transfers; +}; diff --git a/tests/utils/user.js b/tests/utils/user.js new file mode 100644 index 00000000..24e8baeb --- /dev/null +++ b/tests/utils/user.js @@ -0,0 +1,17 @@ +const starkbank = require('../../index.js'); + +exports.exampleProject = new starkbank.Project( + { + environment: 'sandbox', + id: '5656565656565656', + privateKey: `-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIMCwW74H6egQkTiz87WDvLNm7fK/cA+ctA2vg/bbHx3woAcGBSuBBAAK +oUQDQgAE0iaeEHEgr3oTbCfh8U2L+r7zoaeOX964xaAnND5jATGpD/tHec6Oe9U1 +IF16ZoTVt1FzZ8WkYQ3XomRD4HS13A== +-----END EC PRIVATE KEY----- +` + } +); diff --git a/tests/utils/utilityPayment.js b/tests/utils/utilityPayment.js new file mode 100644 index 00000000..dc908b41 --- /dev/null +++ b/tests/utils/utilityPayment.js @@ -0,0 +1,31 @@ +const starkbank = require('../../index.js'); +const random = require('./random.js'); +const check = require('../../sdk/utils/check.js'); + +exampleUtilityPayment = new starkbank.UtilityPayment({ + description: 'Random description', + scheduled: '2020-03-27', + barCode: '83660000001084301380074119002551100010601813', +}); + +function randomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + + +exports.generateExampleUtilityPaymentsJson = function (n, amount = null) { + payments = []; + exampleUtilityPayment = JSON.parse(JSON.stringify(exampleUtilityPayment)); + for (let i = 0; i < n; i++) { + let barCode = '83660000001084301380074119002551100010601813'; + let amountString = random.randomInt(100, 100000).toString(); + let paddedAmount = ('00000000000' + amountString).slice(-11); + exampleUtilityPayment.description = 'abcdefghijklmnopqrstuvwxyz'; + exampleUtilityPayment.barCode = barCode.substring(0, 4) + paddedAmount + barCode.substring(15); + exampleUtilityPayment.scheduled = check.date(random.futureDate(7)); + payments.push(JSON.parse(JSON.stringify(exampleUtilityPayment))); + } + return payments; +}; diff --git a/tests/utils/webhook.js b/tests/utils/webhook.js new file mode 100644 index 00000000..da35970f --- /dev/null +++ b/tests/utils/webhook.js @@ -0,0 +1,9 @@ +const starkbank = require('../../index.js'); + + +exports.generateExampleWebhook = function () { + return new starkbank.Webhook({ + url: 'https://webhook.site/60e9c18e-4b5c-4369-bda1-ab5fcd8e1b29', + subscriptions: ['transfer', 'boleto', 'boleto-payment', 'utility-payment'], + }); +};