diff --git a/.babelrc b/.babelrc index 2f01e1d..1320b9a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,3 @@ { - "presets": ["env"] -} \ No newline at end of file + "presets": ["@babel/preset-env"] +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b735373..9e67458 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,35 +1,43 @@ --- -name: Bug report -about: Create a report to help us improve - +name: Bug Report +about: Help us improve by reporting an issue +labels: [bug, needs-triage] --- -**Describe the bug** -A clear and concise description of what the bug is. +## Bug Description + +A clear and concise description of the issue. + +## Steps to Reproduce -**To Reproduce** -Steps to reproduce the behavior: 1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +2. Click on '...' +3. Scroll down to '...' +4. Observe the issue + +## Expected Behavior + +A clear and concise description of what should happen instead. + +## Screenshots (if applicable) + +Attach screenshots or screen recordings to illustrate the issue. + +## System Information + +### Desktop: -**Expected behavior** -A clear and concise description of what you expected to happen. +- OS: [e.g. Windows 11, macOS Ventura] +- Browser: [e.g. Chrome, Safari] +- Version: [e.g. 120.0.1] -**Screenshots** -If applicable, add screenshots to help explain your problem. +### Mobile: -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] +- Device: [e.g. iPhone 13, Samsung Galaxy S22] +- OS: [e.g. iOS 17, Android 13] +- Browser: [e.g. Chrome, Safari] +- Version: [e.g. 120.0.1] -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +## Additional Context -**Additional context** -Add any other context about the problem here. +Add any other relevant details, logs, or error messages. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 066b2d9..64b4b83 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,17 +1,25 @@ --- -name: Feature request -about: Suggest an idea for this project - +name: Feature Request +about: Suggest an improvement or a new idea for this project +labels: [enhancement, needs-triage] --- -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +## Feature Description + +Provide a clear and concise description of the feature or improvement you are suggesting. + +## Problem Statement + +Is your feature request addressing a specific problem? Clearly describe the issue or limitation. Example: "It is frustrating when [...]" + +## Proposed Solution + +Describe the solution you would like to see implemented. Be as detailed as possible. + +## Alternative Solutions -**Describe the solution you'd like** -A clear and concise description of what you want to happen. +List any alternative approaches or workarounds you have considered. -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +## Additional Context -**Additional context** -Add any other context or screenshots about the feature request here. +Include any other relevant details, references, or screenshots that can help clarify the request. diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml new file mode 100644 index 0000000..673952a --- /dev/null +++ b/.github/workflows/qodana_code_quality.yml @@ -0,0 +1,25 @@ +name: Qodana +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + - npm-standard-lib + +jobs: + qodana: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + checks: write + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + - name: "Qodana Scan" + uses: JetBrains/qodana-action@v2024.3 + env: + QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} diff --git a/.gitignore b/.gitignore index 19375eb..d993cbf 100644 --- a/.gitignore +++ b/.gitignore @@ -26,9 +26,10 @@ bower_components # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release -# Dependency directories +# Dependency directories and lock files node_modules/ jspm_packages/ +package-lock.json # Typescript v1 declaration files typings/ @@ -49,10 +50,11 @@ typings/ .yarn-integrity # dotenv environment variables file -.env +lib/tests/.env.local # yarn error-log yarn-error.log # idea .idea/ + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a99bb25 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,396 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/prettierrc.json", + "definitions": { + "optionsDefinition": { + "type": "object", + "properties": { + "arrowParens": { + "description": "Include parentheses around a sole arrow function parameter.", + "default": "always", + "oneOf": [ + { + "enum": ["always"], + "description": "Always include parens. Example: `(x) => x`" + }, + { + "enum": ["avoid"], + "description": "Omit parens when possible. Example: `x => x`" + } + ] + }, + "bracketSameLine": { + "description": "Put > of opening tags on the last line instead of on a new line.", + "default": false, + "type": "boolean" + }, + "bracketSpacing": { + "description": "Print spaces between brackets.", + "default": true, + "type": "boolean" + }, + "cursorOffset": { + "description": "Print (to stderr) where a cursor at the given position would move to after formatting.", + "default": -1, + "type": "integer" + }, + "embeddedLanguageFormatting": { + "description": "Control how Prettier formats quoted code embedded in the file.", + "default": "auto", + "oneOf": [ + { + "enum": ["auto"], + "description": "Format embedded code if Prettier can automatically identify it." + }, + { + "enum": ["off"], + "description": "Never automatically format embedded code." + } + ] + }, + "endOfLine": { + "description": "Which end of line characters to apply.", + "default": "lf", + "oneOf": [ + { + "enum": ["lf"], + "description": "Line Feed only (\\n), common on Linux and macOS as well as inside git repos" + }, + { + "enum": ["crlf"], + "description": "Carriage Return + Line Feed characters (\\r\\n), common on Windows" + }, + { + "enum": ["cr"], + "description": "Carriage Return character only (\\r), used very rarely" + }, + { + "enum": ["auto"], + "description": "Maintain existing\n(mixed values within one file are normalised by looking at what's used after the first line)" + } + ] + }, + "experimentalTernaries": { + "description": "Use curious ternaries, with the question mark after the condition.", + "default": false, + "type": "boolean" + }, + "filepath": { + "description": "Specify the input filepath. This will be used to do parser inference.", + "type": "string" + }, + "htmlWhitespaceSensitivity": { + "description": "How to handle whitespaces in HTML.", + "default": "css", + "oneOf": [ + { + "enum": ["css"], + "description": "Respect the default value of CSS display property." + }, + { + "enum": ["strict"], + "description": "Whitespaces are considered sensitive." + }, + { + "enum": ["ignore"], + "description": "Whitespaces are considered insensitive." + } + ] + }, + "insertPragma": { + "description": "Insert @format pragma into file's first docblock comment.", + "default": false, + "type": "boolean" + }, + "jsxSingleQuote": { + "description": "Use single quotes in JSX.", + "default": false, + "type": "boolean" + }, + "parser": { + "description": "Which parser to use.", + "anyOf": [ + { + "enum": ["flow"], + "description": "Flow" + }, + { + "enum": ["babel"], + "description": "JavaScript" + }, + { + "enum": ["babel-flow"], + "description": "Flow" + }, + { + "enum": ["babel-ts"], + "description": "TypeScript" + }, + { + "enum": ["typescript"], + "description": "TypeScript" + }, + { + "enum": ["acorn"], + "description": "JavaScript" + }, + { + "enum": ["espree"], + "description": "JavaScript" + }, + { + "enum": ["meriyah"], + "description": "JavaScript" + }, + { + "enum": ["css"], + "description": "CSS" + }, + { + "enum": ["less"], + "description": "Less" + }, + { + "enum": ["scss"], + "description": "SCSS" + }, + { + "enum": ["json"], + "description": "JSON" + }, + { + "enum": ["json5"], + "description": "JSON5" + }, + { + "enum": ["jsonc"], + "description": "JSON with Comments" + }, + { + "enum": ["json-stringify"], + "description": "JSON.stringify" + }, + { + "enum": ["graphql"], + "description": "GraphQL" + }, + { + "enum": ["markdown"], + "description": "Markdown" + }, + { + "enum": ["mdx"], + "description": "MDX" + }, + { + "enum": ["vue"], + "description": "Vue" + }, + { + "enum": ["yaml"], + "description": "YAML" + }, + { + "enum": ["glimmer"], + "description": "Ember / Handlebars" + }, + { + "enum": ["html"], + "description": "HTML" + }, + { + "enum": ["angular"], + "description": "Angular" + }, + { + "enum": ["lwc"], + "description": "Lightning Web Components" + }, + { + "type": "string", + "description": "Custom parser" + } + ] + }, + "plugins": { + "description": "Add a plugin. Multiple plugins can be passed as separate `--plugin`s.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "printWidth": { + "description": "The line length where Prettier will try wrap.", + "default": 80, + "type": "integer" + }, + "proseWrap": { + "description": "How to wrap prose.", + "default": "preserve", + "oneOf": [ + { + "enum": ["always"], + "description": "Wrap prose if it exceeds the print width." + }, + { + "enum": ["never"], + "description": "Do not wrap prose." + }, + { + "enum": ["preserve"], + "description": "Wrap prose as-is." + } + ] + }, + "quoteProps": { + "description": "Change when properties in objects are quoted.", + "default": "as-needed", + "oneOf": [ + { + "enum": ["as-needed"], + "description": "Only add quotes around object properties where required." + }, + { + "enum": ["consistent"], + "description": "If at least one property in an object requires quotes, quote all properties." + }, + { + "enum": ["preserve"], + "description": "Respect the input use of quotes in object properties." + } + ] + }, + "rangeEnd": { + "description": "Format code ending at a given character offset (exclusive).\nThe range will extend forwards to the end of the selected statement.", + "default": null, + "type": "integer" + }, + "rangeStart": { + "description": "Format code starting at a given character offset.\nThe range will extend backwards to the start of the first line containing the selected statement.", + "default": 0, + "type": "integer" + }, + "requirePragma": { + "description": "Require either '@prettier' or '@format' to be present in the file's first docblock comment\nin order for it to be formatted.", + "default": false, + "type": "boolean" + }, + "semi": { + "description": "Print semicolons.", + "default": true, + "type": "boolean" + }, + "singleAttributePerLine": { + "description": "Enforce single attribute per line in HTML, Vue and JSX.", + "default": false, + "type": "boolean" + }, + "singleQuote": { + "description": "Use single quotes instead of double quotes.", + "default": false, + "type": "boolean" + }, + "tabWidth": { + "description": "Number of spaces per indentation level.", + "default": 2, + "type": "integer" + }, + "trailingComma": { + "description": "Print trailing commas wherever possible when multi-line.", + "default": "all", + "oneOf": [ + { + "enum": ["all"], + "description": "Trailing commas wherever possible (including function arguments)." + }, + { + "enum": ["es5"], + "description": "Trailing commas where valid in ES5 (objects, arrays, etc.)" + }, + { + "enum": ["none"], + "description": "No trailing commas." + } + ] + }, + "useTabs": { + "description": "Indent with tabs instead of spaces.", + "default": false, + "type": "boolean" + }, + "vueIndentScriptAndStyle": { + "description": "Indent script and style tags in Vue files.", + "default": false, + "type": "boolean" + } + } + }, + "overridesDefinition": { + "type": "object", + "properties": { + "overrides": { + "type": "array", + "description": "Provide a list of patterns to override prettier configuration.", + "items": { + "type": "object", + "required": ["files"], + "properties": { + "files": { + "description": "Include these files in this override.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "excludeFiles": { + "description": "Exclude these files from this override.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "options": { + "$ref": "#/definitions/optionsDefinition", + "type": "object", + "description": "The options to apply for this override." + } + }, + "additionalProperties": false + } + } + } + } + }, + "oneOf": [ + { + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/optionsDefinition" + }, + { + "$ref": "#/definitions/overridesDefinition" + } + ] + }, + { + "type": "string" + } + ], + "title": "Schema for .prettierrc" +} diff --git a/.travis.yml b/.travis.yml index a3fd835..bd70782 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,13 @@ language: node_js -sudo: false node_js: - - "8.6" + - "20" # Specify the Node.js version or use latest version if you want + +# Install dependencies install: - npm install + +# Run the build step if needed script: - - npm test + - npm run format # Format code + - npm run test # Run dist + - npm run test-integration # Run dist with NYC covergae diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 65126d0..a97f6c1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,45 +2,131 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at apifeedback@safaricom.co.ke. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[apifeedback@safaricom.co.ke](mailto:apifeedback@safaricom.co.ke). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/LICENSE b/LICENSE index 261eeb9..3e341ff 100644 --- a/LICENSE +++ b/LICENSE @@ -180,13 +180,13 @@ To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate + the brackets!) The text Should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2025] [Safaricom] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 8e31e5a..4774983 100644 --- a/README.md +++ b/README.md @@ -1,254 +1,491 @@ # Node.js M-Pesa API + **M-Pesa Library for Node.js using REST API** -![Node Mpesa Rest API](https://i.imgur.com/PRYk4Q3.jpg) +![Node Mpesa Rest API](https://i.imghippo.com/files/fQO9155Kic.jpg) + +
+JavaScript Logo +
-JavaScript Standard Style -[![Build Status](https://travis-ci.org/safaricom/mpesa-node-library.svg?branch=master)](https://travis-ci.org/safaricom/mpesa-node-library) [![Made in Africa](https://img.shields.io/badge/Africa's%20Rising-%E2%9C%93-green.svg)](https://github.com/collections/made-in-africa) [![Known Vulnerabilities](https://snyk.io/test/github/safaricom/mpesa-node-library/badge.svg?targetFile=package.json)](https://snyk.io/test/github/safaricom/mpesa-node-library?targetFile=package.json) +[![npm downloads](https://img.shields.io/npm/dt/your-package-name.svg)](https://www.npmjs.com/package/mpesa-node) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) ## Prerequisites -1. Node v6+, 8+ recommended. -2. Yarn* (optional) You can still use npm -3. ES6 knowledge + +- **Node.js v20+** – Ensure you have Node.js version 20 or later installed for improved performance, security, and + compatibility. +- **Ngrok CLI** – Install the [**Ngrok CLI**](https://download.ngrok.com/) to expose your local server for testing M-Pesa + callbacks. Ensure you have followed the official guide on how to setup Ngrok ## Installation -Use npm/yarn: -``` -npm i mpesa-node -``` -### Pre-Usage +Based on the **package manager** you prefer, run the commands below, to install all necessary dependencies + +**npm**: `npm install` + +**Yarn**: `yarn install` + +## Pre-Usage + +**Please make sure you have read the documentation on [Daraja](https://developer.safaricom.co.ke/home) before +continuing.** -**Please make sure you have read the documentation on [Daraja](https://developer.safaricom.co.ke/home) before continuing.** +You need to sign up for a Safaricom developer [**account**](https://developer.safaricom.co.ke/home) to obtain your **Consumer Key** and **Consumer Secret**. In addition, you'll need to download the **sandbox encryption certificate** to +test the APIs in your project. For production or **going live** you'll be issued with a **production encryption +certificate** -You need the following before getting to use this library: -1. Consumer Key and Consume Secret -2. Test Credentials *(Optional only for sandbox)* +For convenience, the sandbox certificate required for testing the library is already provided in the `libs/cert` +directory _**(For testing the library itself)**_. In your own project, I recommend one to specify the certificate path +in the `.env` for either **production** or **sandbox - development mode**. + +For example, your .env file might look like this: + +```dotenv +# For sandbox/development +MPESA_CERT_PATH_DEV=./path/to/your/sandbox-cert.pem +# For production +MPESA_CERT_PATH_PROD=./path/to/your/production-cert.pem +``` ## Getting Started -This library is extremely modular, meaning you can create more than one Mpesa instance -````js -const Mpesa = require('mpesa-node') -const mpesaApi = new Mpesa({ consumerKey: '', consumerSecret: '' }) -// another instance -// const instance = new Mpesa({ consumerKey: 'test', consumerSecret: 'test', environment: 'production' }) -mpesaApi - .c2bSimulate( - 254708374149, - 500, - 'h6dk0Ue2' - ) - .then((result) => { - //do something - }) - .catch((err) => { - // retry? - }) -```` - -While working with the Mpesa Class, you only need two key-value items, ie: consumerKey and consumerSecret. -Nonetheless, prefilling some things means you dont have to re-enter them again. A complete config object looks like this -````js -new Mpesa({ - consumerKey: '', - consumerSecret: '', - environment: 'sandbox', - shortCode: '600111', - initiatorName: 'Test Initiator', - lipaNaMpesaShortCode: 123456, - lipaNaMpesaShortPass: '', - securityCredential: '', - certPath: path.resolve('keys/myKey.cert') -}) -```` -## API -Please note that this library is in active development, use in production with caution. - -Current API: -````js -const mpesaApi = new Mpesa({ consumerKey: '', consumerSecret: '' }) -const { - accountBalance, - b2b, - b2c, - c2bRegister, - c2bSimulate, - lipaNaMpesaOnline, - lipaNaMpesaQuery, - reversal, - transactionStatus -} = mpesaApi -```` -Ofcourse you dont need to import all methods, you can import the only ones you need. - -All methods return a ``, hence you can use `.then` or `await`. -All calls are done by Axios, so for the response structure check Axios documentation. - -### Methods -• [B2C Request](https://developer.safaricom.co.ke/b2c/apis/post/paymentrequest) - -This initiates a business to customer transactions from a company (shortcode) to end users (mobile numbers) of their services. -````js -/* - * b2c(senderParty, receiverParty, amount, queueUrl, resultUrl, commandId = 'BusinessPayment', initiatorName = null, remarks = 'B2C Payment', occasion = null) - * Example: -*/ -const { shortCode } = mpesaApi.configs -const testMSISDN = 254708374149 -await mpesaApi.b2c(shortCode, testMSISDN, 100, URL + '/b2c/timeout', URL + '/b2c/success') -```` - -• [B2B Request](https://developer.safaricom.co.ke/b2b/apis/post/paymentrequest) - -This initiates a business to business transaction between one company to another. -````js -/* - * b2c(senderParty, receiverParty, amount, queueUrl, resultUrl, senderType = 4, receiverType = 4, initiator = null, commandId = 'BusinessToBusinessTransfer', accountRef = null, remarks = 'B2B Request') - * Example: -*/ -const { shortCode } = mpesaApi.configs -const testShortcode2 = 600000 -await mpesaApi.b2b(shortCode, testShortcode2, 100, URL + '/b2b/timeout', URL + '/b2b/success') -```` -• [C2B Register](https://developer.safaricom.co.ke/c2b/apis/post/registerurl) - -This initiates a C2B confirmation and validation registration for a company's URLs - -````js -/* - * c2bRegister(confirmationUrl, validationUrl, shortCode = null, responseType = 'Completed') - * Example: - */ -await mpesaApi.c2bRegister(URL + '/c2b/validation', URL + '/c2b/success') +**Note:** This library follows a **modular approach**, allowing you to import only the **specific functions or endpoints** you need. Before getting started, make sure the following steps are **properly set up** ✔. -```` +### Setting up environmental credentials -• [C2B Simulate](https://developer.safaricom.co.ke/c2b/apis/post/simulate) +A `.env` file in your project's root directory is required to configure the **M-Pesa API** credentials. This file **should** +contain the following environment variables -This initiates a C2B transaction between an end-user and a company (paybill or till number) +```dotenv +MPESA_CONSUMER_KEY=your_consumer_key +MPESA_CONSUMER_SECRET=your_consumer_secret +MPESA_SECURITY_CREDENTIAL=your_encrypted_credential +MPESA_PASS_KEY=your_pass_key +MPESA_CERT_PATH_DEV=./certs/dev-cert.pem +MPESA_CERT_PATH_PROD=./certs/prod-cert.pem +ENVIRONMENT=sandbox +``` -````js -/* - * c2bSimulate(msisdn, amount, billRefNumber, commandId = 'CustomerPayBillOnline', shortCode = null) - * Example: - */ -const testMSISDN = 254708374149 -await mPesa.c2bSimulate(testMSISDN, 100, Math.random().toString(35).substr(2, 7)) +The `MPESA_PASS_KEY` Can be found specifically here [**Daraja**](https://developer.safaricom.co.ke/APIs/MpesaExpressSimulate) - _(my Apis - MpesaExpressSimulate)_. Click on the **console**, select an app, scroll down you'll see the field labeled `passKey` -```` -• [M-Pesa Express Request - Lipa Na M-Pesa Online Payment API](https://developer.safaricom.co.ke/lipa-na-m-pesa-online/apis/post/stkpush/v1/processrequest) +**Note for Library Developers**: If you're contributing to or working on the **M-Pesa** library itself, place a +`.env.local` or `.env` file in the `lib/tests` directory to run the included tests. This is not required for simply using the APIs +in your own projects. -This initiates a Lipa Na M-Pesa Online Payment transaction using STK Push. +## Simulating an account balance check: -````js -/* - * lipaNaMpesaOnline(senderMsisdn, amount, callbackUrl, accountRef, transactionDesc = 'Lipa na mpesa online', transactionType = 'CustomerPayBillOnline', shortCode = null, passKey = null) - * Example: +You can simulate an account balance check by importing and calling the `balanceQuery` function, together with its +callback handler (optional) `handleBalanceQueryCallbacks` + +**TypeScript Support:** This library has a `.d.ts` for each **API endpoint**, providing seamless integration and type +checking for TypeScript projects. + +Below is an example of how to set up the account balance api endpoint `balanceQuery`: + +```js +import { mpesa } from "mpesa-node"; + +// Account Balance Query Example +/** + * @name balanceQuery + * @description Fetches the account balance from M-Pesa. + * @see {@link https://developer.safaricom.co.ke/APIs/AccountBalance} - Daraja API Documentation */ - const testMSISDN = 254708374149 - const amount = 100 - const accountRef = Math.random().toString(35).substr(2, 7) -await mpesaApi.lipaNaMpesaOnline(testMSISDN, amount, URL + '/lipanampesa/success', accountRef) -```` -• [M-Pesa Express Query Request - Lipa Na M-Pesa Query Request API](https://developer.safaricom.co.ke/lipa-na-m-pesa-online/apis/post/stkpushquery/v1/query) +const { balanceQuery } = mpesa; + +// Ensure you replace these placeholders with valid values +// For the url, check on how to handle callbacks, paste the url provided below +const VALID_HTTPS_URL = "paste here"; +const INITIATOR_NAME = "yourInitiatorUsername"; + +async function checkAccountBalance() { + try { + const response = await balanceQuery({ + idType: 2, // Example: 2 (Till Number) + shortCode: 600977, + initiator: INITIATOR_NAME, + queueURL: `${VALID_HTTPS_URL}/accountbalance/queuetimeouturl`, + resultURL: `${VALID_HTTPS_URL}/accountbalance/result`, + }); + //do something ... + console.log("Account Balance Response:", JSON.stringify(response, null, 2)); + } catch (error) { + //do something... + console.error("Error fetching account balance:", error); + } +} +// Execute the function +checkAccountBalance(); +``` -This API checks the status of a Lipa Na M-Pesa Online Payment transaction +### Handling callbacks -````js -/* - * lipaNaMpesaQuery(checkoutRequestId, shortCode = null, passKey = null) - * Example: +After setting up the `balanceQuery` endpoint, lets configure the callback handler associated with it; `handleBalanceQueryCallbacks`. A **server instance** is required to use callback handlers +. For this to work, ensure you have **ngrok CLI** +installed on your machine, see [**getting started with Ngrok**](https://ngrok.com/docs/getting-started/) + +Using the library's default callback handlers is **completely optional**—you're free to handle them `manually` if +preferred. + +```js +import express from "express"; +import { callbacks } from "mpesa-node"; + +const app = express(); +const { handleBalanceQueryCallbacks } = callbacks; + +// Middleware for parsing JSON requests +app.use(express.json()); + +// Register M-Pesa balance query callback handler +handleBalanceQueryCallbacks(app); + +/** + * STARTING THE SERVER + * ------------------- + * - The server listens on port 3000 (or an environment-defined port) + * - Developers can use tools like `ngrok` to expose the server publicly for testing callbacks */ -const checkoutRequestId ='ws_co_123456789' -await mpesaApi.lipaNaMpesaQuery(checkoutRequestId) -```` -• [Reversal Request](https://developer.safaricom.co.ke/reversal/apis/post/request) +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); + console.log(`To expose this locally, run: ngrok http ${PORT}`); + console.log( + `Ensure the public URL provided by ngrok is set as the 'resultURL' and 'queueURL' in your M-Pesa request`, + ); +}); +``` -This initiates an M-Pesa transaction reversal on B2B, B2C or C2B API -````js +When using the default **callback handlers**, the response includes the main API `balanceQuery` response body, along with either a **result** or **queue** callback body. + +```js +const response = await balanceQuery({ + idType: 2, // Example: 2 (Till Number) + shortCode: 600977, + initiator: INITIATOR_NAME, + queueURL: `${VALID_HTTPS_URL}/accountbalance/queuetimeouturl`, + resultURL: `${VALID_HTTPS_URL}/accountbalance/result`, +}); +//do something ... +console.log("Account Balance Response:", JSON.stringify(response, null, 2)); /* - * reversal(transactionId, amount, queueUrl, resultUrl, shortCode = null, remarks = 'Reversal', occasion = 'Reversal', initiator = null, receiverIdType = '11', commandId = 'TransactionReversal') - * Example: - */ -await mpesaApi.reversal('LKXXXX1234', 100, URL + '/reversal/timeout', URL + '/reversal/success') -```` -• [Transaction Status Request](https://developer.safaricom.co.ke/transaction-status/apis/post/query) + if callback handlers are used expect such a json response... + "Account balance response": { + "balanceResponse": { + ...some data + }, + "conditionalCallbackData": { + "type": "result or queue", + "data": { + ...some data + } + } + } + if callback handlers aren't used simply expect + "Account balance response": { + "balanceResponse": { + ...some data + }, + "conditionalCallbackData": {} + */ +``` -This API is used to check the status of B2B, B2C and C2B transactions +**NOTE**: At all costs avoid using URLs offered by **Ngrok** for **production** or **going live** + +## Supported API endpoints: + +#### Caution! + +This library is still in development. We recommend **thorough testing** before using it in a **production environment**. + +Here is a comprehensive list of all supported API endpoints with their respective documentation links: + +- **balanceQuery**: [**Daraja**](https://developer.safaricom.co.ke/APIs/AccountBalance) + or [**JsDocs**](./docs/balance-Query.js.html) +- **b2cRequest**: [**Daraja**](https://developer.safaricom.co.ke/APIs/BusinessToCustomer) + or [**JsDocs**](./docs/b2c-Request.js.html) +- **c2bRegister**: [**Daraja**](https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL) + or [**JsDocs**](./docs/c2b-Register.js.html) +- **c2bSimulate**: [**Daraja**](https://developer.safaricom.co.ke/c2b/apis/post/simulate) + or [**JsDocs**](./docs/c2b-Simulate.js.html) +- **mpesaSimulate**: [**Daraja**](https://developer.safaricom.co.ke/c2b/apis/post/simulate) + or [**JsDocs**](./docs/c2b-Simulate.js.html) +- **mpesaQuery**: [**Daraja**](https://developer.safaricom.co.ke/c2b/apis/post/simulate) + or [**JsDocs**](./docs/c2b-Simulate.js.html) +- **reversals**: [**Daraja**](https://developer.safaricom.co.ke/APIs/MpesaExpressQuery) + or [**JsDocs**](./docs/reversals.js.html) +- **generateQrCode**: [**Daraja**](https://developer.safaricom.co.ke/APIs/DynamicQRCode) + or [**JsDocs**](./docs/qr-Generate.js.html) +- **transactionStatus**: [**Daraja**](https://developer.safaricom.co.ke/transaction-status/apis/post/query) + or [**JsDocs**](./docs/transaction-Status.js.html) +- **b2cTopUp**: [**Daraja**](https://developer.safaricom.co.ke/transaction-status/apis/post/query) + or [**JsDocs**](./docs/b2c-Topup.js.html) +- **businessPaybill**: [**Daraja**](https://developer.safaricom.co.ke/APIs/BusinessPayBill) + or [**JsDocs**](./docs/business-Paybill.js.html) +- **taxRemittance**: [**Daraja**](https://developer.safaricom.co.ke/APIs/TaxRemittance) + or [**JsDocs**](https://developer.safaricom.co.ke/APIs/TaxRemittance) + +Developers are strongly encouraged to consult the [**JsDocs**](./docs/global.html) (_which comes bundled with the library_) for detailed information on how the required fields are mapped. This documentation clearly outlines the necessary configurations for successfully initiating any endpoint, ensuring a smooth integration process. + +### Options for each API + +Here is a comprehensive list of all supported APIs along with their respective **options**. Use this as a reference when configuring the parameters for your chosen API. + +```ts +export interface balanceQueryOptions { + partyA: number; + identifierType: number; + QueueTimeOutURL: string; + resultURL: string; + initiator: string; + remarks: string; +} + +export interface b2cRequestOptions { + partyA: number; + partyB: string; + amount: number; + QueueTimeOutURL: string; + resultURL: string; + commandId: string; + initiatorName: string; + remarks: string; + occasion: string; +} + +export interface c2bRegisterOptions { + confirmationURL: string; + validationURL: string; + shortCode: number; + responseType: string; +} + +export interface c2bSimulateOptions { + msisdn: string; + amount: number; + billRefNumber: string; + shortCode: number; +} + +export interface mpesaSimulateOptions { + partyA: string; + phoneNumber: string; + amount: number; + callbackURL: string; + accountRef: string; + transactionType: string; + partyB: number; + transactionDesc: string; +} + +export interface mpesaQueryOptions { + checkoutRequestId: string; + businessShortCode: number; +} + +export interface reversalsOptions { + transactionId: string; + amount: number; + QueueTimeOutURL: string; + resultURL: string; + receiverParty: string; + initiator: string; + receiverIdType: string; + remarks: string; + occasion: string; +} + +export interface transactionStatusOptions { + transactionId: string; + partyA: number; + identifierType: number; + QueueTimeOutURL: string; + resultURL: string; + initiator: string; + OriginatorConversationID: string; + remarks: string; + occasion: string; +} + +export interface generateQrCodeOptions { + merchantName: string; + refNo: string; + amount: number; + trxCode: "BG" | "WA" | "PB" | "SM" | "SB"; + cpi: string; + size: string; +} + +export interface b2cTopUpOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + requester?: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} + +export interface businessPaybillOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + requester?: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} + +export interface taxRemittanceOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} +``` -````js -/* - * transactionStatus(transactionId, receiverParty, idType, queueUrl, resultUrl, remarks = 'TransactionReversal', occasion = 'TransactionReversal', initiator = null, commandId = 'TransactionStatusQuery') - * Example: - */ -await mpesaApi.transactionStatus('LKXXXX1234', shortCode, 4, URL + '/transactionstatus/timeout', URL + '/transactionstatus/success') -```` -• [Account Balance Request](https://developer.safaricom.co.ke/account-balance/apis/post/query) +### MSISDN formatting -This initiates a request for the account balance of a shortcode +When working with APIs that require an `msisdn` (a **phone number**), always provide it as a `string` in the format: `0708374149`. The library automatically processes the number into the required format, so no additional configuration is needed. + +### External configurations + +Certain endpoints require external configurations to function correctly, particularly when working in a production environment. For seamless integration and optimal performance, it is crucial to review the API documentation thoroughly. Some APIs, such as **taxRemittance**, **b2cRequest** and **c2bRegister**, may depend on additional setup or external parameters that are necessary for proper functionality. + +In a **production development** setting, these configurations are especially critical to ensure that all aspects of the API perform as expected. It is highly recommended that developers pay close attention to the specific requirements outlined in the [**official documentation**](https://developer.safaricom.co.ke/APIs) for each API. Relying on the most up-to-date and detailed guidelines from the official sources will help mitigate potential issues and ensure smooth integration. -````js -/* - * accountBalance(shortCode, idType, queueUrl, resultUrl, remarks = 'Checking account balance', initiator = null, commandId = 'AccountBalance') - * Example: - */ -const { shortCode } = mpesaApi.configs -await mpesaApi.accountBalance(shortCode, 4, URL + '/accountbalance/timeout', URL + '/accountbalance/success') -```` ## Testing -Testing needs you to clone this repo. -The command below runs both integration and unit test. +This library is built around **integration tests**, following a **Behavior-Driven Development (BDD)** approach. + +This approach is ideal for a wide range of audiences because **BDD focuses** on clear, human-readable test scenarios +that describe expected behaviors. Additionally, integration tests validate real-world interactions, ensuring the library +works reliably in actual usage scenarios. + +**BDD approach** + **on integration tests**, can help: + +- Catch authentication issues (**OAuth failures**) +- Verify actual API responses (**instead of mocked ones**) +- Check if callbacks are received & handled properly +- Detect network timeouts or incorrect response formats + +To run tests, first, **clone this repository**. + +The command below (_based on your package manager_) executes **integration tests**, which **require an active internet +connection** to accurately simulate **real API interactions** over **HTTPS**. + +**npm**: `npm test` + +**Yarn**: `yarn test` + +### Activating callback handlers in tests -Integration tests launch a ngrok instance and await callbacks (you will need an active internet connection for this). +Callback handlers in **testing** are automatically configured but **disabled** by default. -To run each separately, check `package.json` for the commands. -```` -npm test -```` -## Going Live/Production +Below is an example of a `c2bSimulate` **mocha** test. To activate callback handling swap `true` to `false`. -You will need to first click on "Going Live" on [Daraja](https://developer.safaricom.co.ke/user/me/apps) +```js +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { setupNgrokServer } from "../utils/server.js"; +import { createOptionsForC2bSimulate } from "../utils/options.js"; -The only thing you need to tweek in this Libs config is `environment`: -````js -new Mpesa({ - consumerKey: '', - consumerSecret: '', - environment: 'production', //<------ - ..... - }) -```` +describe("C2B Simulate API with OAuth", function () { + this.timeout(28000); + let NGROK_URL, teardown; + const { c2bSimulate } = mpesa; + + // To enable callback handling swap true to false + before(async function () { + // ({ NGROK_URL, teardown } = await setupNgrokServer("c2bSimulate", true)); + ({ NGROK_URL, teardown } = await setupNgrokServer("c2bSimulate", false)); + }); + + after(async function () { + await teardown(); + }); + + it("Should simulate a C2B transaction", function (done) { + c2bSimulate( + createOptionsForC2bSimulate( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); +``` + +### Temporary port exposure + +Once the callback handler is enabled, the boolean option (`false` allows the test to temporarily: + +- Spawn a local server +- Expose it via Ngrok +- Fetch responses from API endpoint servers + +This setup ensures that callbacks are properly handled during testing. + +## Production environment (Going live) + +Before **deploying** to **production**, successful **sandbox testing** is essential. We **expect** the library to behave +**consistently** in both environments, with the key difference being that production callbacks will contain real +transaction data, whereas sandbox callbacks return simulated responses. + +To **go live**, log in to [**Daraja**](https://developer.safaricom.co.ke/) and click on +the "[**Going Live**](https://developer.safaricom.co.ke/GoLive)" option. + +For this to work properly, you need to tweak the `ENVIRONMENT` option to `"production"` and `MPESA_CERT_PATH_PROD` to a +valid `"/production.cer"` path, in the `.env` file: + +```dotenv +ENVIRONMENT=production +MPESA_CERT_PATH_PROD=./path/to/your/production-cert.pem +``` ## Pending Stuff -- [x] E2E Integration Tests -- [x] Deploy to Npm -- [x] Reduce number of args -- [x] Detailed Documentation -- [ ] Enumify -- [ ] Validators for MSISDN and other expected inputs -- [x] More detailed Unit tests -- [ ] Handle all Promises +- [x] **Integration Tests** +- [x] **Deploy to Npm** +- [x] **Detailed Documentation** +- [x] **Typescript Definitions** +- [x] **Validators for MSISDN and URLs** +- [ ] **Production testing** ## Contributing -1. Create your feature branch: `git checkout -b my-new-feature` -2. Commit your changes: `git commit -m 'Add some feature'` -3. Push to the branch: `git push origin my-new-feature` -4. Submit a pull request :D + +We welcome **contributions**! Follow these steps to get started: + +1. **Create** your feature branch: `git checkout -b my-new-feature` +2. **Commit** your changes: `git commit -m 'Add some feature'` +3. **Push** to the branch: `git push origin my-new-feature` +4. Open a **pull request** and share your updates ## Credits -| **Contributor** | -
-| [DGatere](https://github.com/DGatere) |
-| [geofmureithi](https://github.com/geofmureithi) | +**Contributors** +- [DGatere](https://github.com/DGatere) +- [geofmureithi](https://github.com/geofmureithi) +- [Waturu Samm](https://github.com/tu-ru/) ## License -MIT +**APACHE 2.0** diff --git a/docs/b2c-Request.js.html b/docs/b2c-Request.js.html new file mode 100644 index 0000000..bcba7de --- /dev/null +++ b/docs/b2c-Request.js.html @@ -0,0 +1,261 @@ + + + + + + b2c-Request.js - Documentation + + + + + + + + + + + + + + + + +
+

b2c-Request.js

+ +
+
+
import axios from "axios";
+import { CommandIDs } from "../utils/constants.js";
+import {
+  callbackTrigger,
+  encryptSecurityCredential,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  originatorID,
+  throwErrorMessages, validateFormatPhone,
+  validateUrl
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name b2cRequest
+ * @description B2C API can be used in several scenarios by businesses that require to either make Salary Payments, Cashback payments, Promotional Payments(e.g. betting winning payouts), winnings, financial institutions withdrawal of funds, loan disbursements, etc.
+ * @summary B2C payments involve a business sending money to an individual. This is a direct transaction from a business shortcode to a consumer's mobile number (MSISDN).
+ * @see {@link https://developer.safaricom.co.ke/APIs/BusinessToCustomer open external link}
+ * @param {Object} options Options for the B2C payment request.
+ * @param {number} options.partyA The B2C organization shortcode sending the money.
+ * @param {string} options.partyB Customer mobile number (with country code, e.g., 254).
+ * @param {number} options.amount The amount being transacted.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {string} options.occasion Information to be associated with the transaction.
+ * @param {string} options.QueueTimeOutURL URL for timeout notifications.
+ * @param {string} options.resultURL URL for M-PESA to send payment processing notifications.
+ * @param {string} options.commandId Unique command specifying B2C transaction type (e.g., BusinessPayment).
+ * @param {string} options.initiatorName API user created by Business Administrator for B2C transactions.
+ * @param {boolean} [options.proErrorLogging=false] Logs out advanced error details - good for debugging.
+ * @return {Promise<object>} b2cRequestResponse and (optional) conditionalCallbackData. */
+async function b2cRequest({
+  partyA,
+  partyB,
+  amount,
+  QueueTimeOutURL,
+  remarks,
+  occasion,
+  resultURL,
+  commandId,
+  initiatorName,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleB2cRequestCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  /**
+   * @param {string} validCommandIds - loops through object values with strings "SalaryPayment", "BusinessPayment" PromotionPayment"
+   */
+  const validCommandIds = Object.values(CommandIDs);
+  if (!validCommandIds.includes(commandId)) {
+    throw new Error(
+      `Invalid commandId provided. Must be one of: ${validCommandIds.join(", ")}`,
+    );
+  }
+  const _msisdn = validateFormatPhone(partyB)
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "QueueTimeOutURL");
+    const OriginatorConversationID = originatorID();
+    const { accessToken, baseURL } = await generateOAuthToken();
+
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+
+    const responseBody = await req.post("/mpesa/b2c/v3/paymentrequest", {
+      OriginatorConversationID,
+      InitiatorName: initiatorName,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: commandId,
+      Amount: amount,
+      PartyA: partyA,
+      PartyB: _msisdn,
+      Remarks: remarks,
+      QueueTimeOutURL: QueueTimeOutURL,
+      ResultURL: resultURL,
+      Occasion: occasion
+    });
+
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+
+    return { b2cRequestResponse: responseBody.data, conditionalCallbackData};
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for b2cRequest has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/b2c/v3/paymentrequest",
+          method: "POST",
+          payload: {
+            partyA,
+            _msisdn,
+            amount,
+            QueueTimeOutURL,
+            resultURL,
+            commandId,
+            initiatorName,
+            occasion,
+            remarks
+          },
+        },
+        "B2C transaction error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+const handleB2cRequestCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "b2cRequest");
+};
+export { b2cRequest, handleB2cRequestCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/b2c-Topup.js.html b/docs/b2c-Topup.js.html new file mode 100644 index 0000000..5fe7b5b --- /dev/null +++ b/docs/b2c-Topup.js.html @@ -0,0 +1,257 @@ + + + + + + b2c-Topup.js - Documentation + + + + + + + + + + + + + + + + +
+

b2c-Topup.js

+ +
+
+
import axios from "axios";
+import {
+  generateOAuthToken,
+  encryptSecurityCredential,
+  throwErrorMessages,
+  logErrorDetails,
+  callbackTrigger,
+  handleCallbacks,
+  validateUrl,
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ *@name b2cTopUp
+ *@description This API enables you to load funds to a B2C shortcode directly for disbursement. The transaction moves money from your MMF/Working account to the recipient’s utility account.
+ *@summary Transfers funds from your MMF/Working account to the recipient's utility account for disbursement to a B2C shortcode.
+ * @see {@link https://developer.safaricom.co.ke/APIs/B2CAccountTopUp open external link}
+ * @param {Object} options B2C account top-up request options.
+ * @param {string} options.initiator The M-Pesa API operator username, who needs Org Business Pay to Bulk API initiator role.
+ * @param {number} options.amount The transaction amount.
+ * @param {number} options.partyA Your shortcode. The shortcode from which money will be deducted.
+ * @param {number} options.partyB The shortcode to which money will be moved
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {number} options.accountReference Identifier for the transaction.
+ * @param {number} [options.requester] Optional. The consumer’s mobile number on behalf of whom you are paying.
+ * @param {string} options.QueueTimeOutURL A URL that will be used to notify your system in case the request times out.
+ * @param {string} options.resultURL A URL that will be used to send transaction results after processing.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @return {Promise<object>} b2cTopUpResponse and (optional) conditionalCallbackData. */
+async function b2cTopUp({
+  initiator,
+  amount,
+  partyA,
+  partyB,
+  accountReference,
+  requester,
+  QueueTimeOutURL,
+  resultURL,
+  remarks,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleB2cTopUpCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "QueueTimeOutUrl");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+
+    // Default configurations
+    const config = {
+      commandId: "BusinessPayToBulk",
+      senderIdentifierType: "4",
+      receiverIdentifierType: "4",
+    };
+
+    const responseBody = await req.post("mpesa/b2b/v1/paymentrequest", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      SenderIdentifierType: config.senderIdentifierType,
+      RecieverIdentifierType: config.receiverIdentifierType,
+      Amount: amount,
+      PartyA: partyA,
+      PartyB: partyB,
+      AccountReference: accountReference,
+      Requester: requester,
+      Remarks: remarks,
+      QueueTimeOutURL: QueueTimeOutURL,
+      ResultURL: resultURL,
+    });
+
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+
+    return { b2cTopUpResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for b2cTopUp has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/b2b/v1/paymentrequest",
+          method: "POST",
+          payload: {
+            initiator,
+            amount,
+            partyA,
+            partyB,
+            accountReference,
+            requester,
+            QueueTimeOutURL,
+            resultURL,
+            remarks
+          },
+        },
+        "B2C account top-up error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleB2cTopUpCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "b2cTopUp");
+};
+export { b2cTopUp, handleB2cTopUpCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/balance-Query.js.html b/docs/balance-Query.js.html new file mode 100644 index 0000000..8e0957a --- /dev/null +++ b/docs/balance-Query.js.html @@ -0,0 +1,248 @@ + + + + + + balance-Query.js - Documentation + + + + + + + + + + + + + + + + +
+

balance-Query.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  encryptSecurityCredential,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+  validateUrl,
+} from "../utils/helpers.js";
+import { IdentifierTypes } from "../utils/constants.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name balanceQuery
+ * @description The Account Balance API is used to request the account balance of a short code. This can be used for both B2C, buy goods and pay bill accounts.
+ * @summary Retrieves the balance of a short code associated with the developer account, supporting B2C, buy goods, and pay bill accounts.
+ * @see {@link https://developer.safaricom.co.ke/APIs/AccountBalance open external link}
+ * @param {Object} options Options for the balance query API.
+ * @param {number} options.partyA The shortcode of the querying organization.
+ * @param {number} options.identifierType Type of the querying organization.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {String} options.QueueTimeOutURL URL to receive timeout messages.
+ * @param {String} options.resultURL URL to receive the result message.
+ * @param {String} options.initiator The credential/username for authentication.
+ * @param {boolean} [options.proErrorLogging=false] Logs out advanced error details - good for debugging
+ * @return {Promise<object>} balanceQueryResponse and (optional) conditionalCallbackData.
+ */
+async function balanceQuery({
+  partyA,
+  identifierType,
+  QueueTimeOutURL,
+  resultURL,
+  initiator,
+  remarks,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleBalanceQueryCallbacks') was not called. Ignore if handling manually.\x1b[0m"
+    );
+  }
+  /**
+   * @param {number} validIdentifierTypes - Expected identifiers include const IdentifierTypes = { MSISDN: 1, TILL_NUMBER: 2, ORG_SHORTCODE: 4 };
+   */
+  const validIdentifierTypes = Object.values(IdentifierTypes);
+  if (!validIdentifierTypes.includes(identifierType)) {
+    throw new Error(
+      `Invalid identifierType provided. Must be one of: ${validIdentifierTypes.join(", ")}`,
+    );
+  }
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "timeoutUrl");
+    const { accessToken, baseURL } = await generateOAuthToken();
+
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+
+    // Default configurations
+    const config = {
+      commandId: "AccountBalance",
+      remarks: "OK",
+    };
+
+    const responseBody = await req.post("/mpesa/accountbalance/v1/query", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      PartyA: partyA,
+      IdentifierType: identifierType,
+      Remarks: remarks,
+      QueueTimeOutURL: QueueTimeOutURL,
+      ResultURL: resultURL,
+    });
+
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+
+    return { balanceQueryResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for balanceQuery has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/accountbalance/v1/query",
+          method: "POST",
+          payload: { partyA, identifierType, QueueTimeOutURL, resultURL, initiator, remarks },
+        },
+        "Balance query error details:",
+      );
+    }
+    throw await throwErrorMessages(error);
+  }
+}
+
+const handleBalanceQueryCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "balanceQuery");
+};
+
+export { balanceQuery, handleBalanceQueryCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/business-Paybill.js.html b/docs/business-Paybill.js.html new file mode 100644 index 0000000..3753140 --- /dev/null +++ b/docs/business-Paybill.js.html @@ -0,0 +1,260 @@ + + + + + + business-Paybill.js - Documentation + + + + + + + + + + + + + + + + +
+

business-Paybill.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  encryptSecurityCredential,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+  validateUrl,
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name businessPaybill
+ * @description This API enables you to pay bills directly from your business account to a pay bill number, or a paybill store. You can use this API to pay on behalf of a consumer/requester. The transaction moves money from your MMF/Working account to the recipient’s utility account.
+ * @summary  Facilitates bill payments from a business account to a paybill number, transferring funds to the recipient’s utility account.
+ * @see {@link https://developer.safaricom.co.ke/APIs/BusinessPayBill open external link}
+ * @param {Object} options Options for the business pay bill.
+ * @param {string} options.initiator M-Pesa API operator username with Org Business Pay Bill API role.
+ * @param {number} options.amount Transaction amount.
+ * @param {number} options.partyA Shortcode from which money will be deducted.
+ * @param {number} options.partyB Shortcode to which money will be moved.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {number} options.accountReference Account number for the payment (up to 13 characters).
+ * @param {number} [options.requester] Optional consumer’s mobile number (if paying on their behalf).
+ * @param {string} options.QueueTimeOutURL URL for timeout notifications.
+ * @param {string} options.resultURL URL for sending transaction results after processing.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @return {Promise<Object>} businessPaybillResponse and (optional) conditionalCallbackData.
+ */
+async function businessPaybill({
+  initiator,
+  amount,
+  partyA,
+  partyB,
+  remarks,
+  accountReference,
+  requester,
+  QueueTimeOutURL,
+  resultURL,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleBusinessPaybillCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "timeoutUrl");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    // Default configurations
+    const config = {
+      commandId: "BusinessPayBill",
+      senderIdentifierType: "4",
+      receiverIdentifierType: "4",
+    };
+    const responseBody = await req.post("/mpesa/b2b/v1/paymentrequest", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      SenderIdentifierType: config.senderIdentifierType,
+      RecieverIdentifierType: config.receiverIdentifierType,
+      Amount: amount,
+      PartyA: partyA,
+      PartyB: partyB,
+      AccountReference: accountReference,
+      Requester: requester,
+      Remarks: remarks,
+      QueueTimeOutURL: QueueTimeOutURL,
+      ResultURL: resultURL,
+    });
+
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+
+    return {
+      businessPaybillResponse: responseBody.data,
+      conditionalCallbackData,
+    };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for businessPaybill has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/b2b/v1/paymentrequest",
+          method: "POST",
+          payload: {
+            initiator,
+            amount,
+            partyA,
+            partyB,
+            accountReference,
+            requester,
+            QueueTimeOutURL,
+            resultURL,
+            remarks
+          },
+        },
+        "Business Pay Bill transaction error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleBusinessPaybillCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "businessPaybill");
+};
+
+export { businessPaybill, handleBusinessPaybillCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/c2b-Register.js.html b/docs/c2b-Register.js.html new file mode 100644 index 0000000..c91a63f --- /dev/null +++ b/docs/c2b-Register.js.html @@ -0,0 +1,234 @@ + + + + + + c2b-Register.js - Documentation + + + + + + + + + + + + + + + + +
+

c2b-Register.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+  validateUrl,
+} from "../utils/helpers.js";
+import { responseTypes } from "../utils/constants.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name C2BRegister
+ * @description Register URL API works hand in hand with Customer to Business (C2B) APIs and allows receiving payment notifications to your paybill. This API enables you to register the callback URLs via which you shall receive notifications for payments to your pay bill/till numbers
+ * @summary Registers callback validation and confirmation URLs on M-Pesa to receive payment notifications for your paybill/till numbers.
+ * @see {@link https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL open external link}
+ * @param {Object} options Options for the C2B Register URL.
+ * @param {string} options.confirmationURL URL to receive confirmation upon payment completion.
+ * @param {string} options.validationURL URL to receive validation upon payment submission (default: external validation disabled).
+ * @param {number} options.shortCode Unique M-PESA pay bill/till number.
+ * @param {string} options.responseType Action if validation URL is unreachable (values: Completed or Cancelled).
+ * @param {boolean} [options.proErrorLogging] Logs out detailed errors for debugging purposes
+ * @return {Promise<Object>} c2bRegisterResponse and (optional) conditionalCallbackData.
+ */
+async function c2bRegister({
+  confirmationURL,
+  validationURL,
+  shortCode,
+  responseType,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleC2bRegisterCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  /**
+   * @param {string} validResponseTypes - Should either be Completed or Cancelled
+   */
+  const validResponseTypes = Object.values(responseTypes);
+  if (!validResponseTypes.includes(responseType)) {
+    throw new Error(
+      `Invalid responseType provided. Must be one of: ${validResponseTypes.join(", ")}`,
+    );
+  }
+  try {
+    validateUrl(confirmationURL, "confirmationURL");
+    validateUrl(validationURL, "validationURL");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    const responseBody = await req.post("/mpesa/c2b/v1/registerurl", {
+      ShortCode: shortCode,
+      ResponseType: responseType,
+      ConfirmationURL: confirmationURL,
+      ValidationURL: validationURL,
+    });
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+    return { c2bRegisterResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for c2bRegister has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/c2b/v1/registerurl",
+          method: "POST",
+          payload: {
+            confirmationURL,
+            validationURL,
+            shortCode,
+            responseType,
+          },
+        },
+        "C2B Register transaction error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleC2bRegisterCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "c2bRegister");
+};
+
+export { c2bRegister, handleC2bRegisterCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/c2b-Simulate.js.html b/docs/c2b-Simulate.js.html new file mode 100644 index 0000000..0316fc6 --- /dev/null +++ b/docs/c2b-Simulate.js.html @@ -0,0 +1,212 @@ + + + + + + c2b-Simulate.js - Documentation + + + + + + + + + + + + + + + + +
+

c2b-Simulate.js

+ +
+
+
import {
+  generateOAuthToken, logErrorDetails,
+  throwErrorMessages,
+  validateFormatPhone
+} from "../utils/helpers.js";
+import axios from "axios";
+
+
+/**
+ * @name c2bSimulate
+ * @description This function simulates a C2B (Customer to Business) transaction by initiating a payment from an MSISDN to a business shortcode.
+ * @summary Simulate a transaction from an MSISDN to a business shortcode
+ * @see {@link https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL open external link}
+ * @param {Object} options Options for the C2B simulation.
+ * @param {string} options.msisdn The MSISDN receiving the transaction
+ * @param {number} options.amount Transaction amount.
+ * @param {string} options.billRefNumber Bill reference number e.g. "invoice008".
+ * @param {number} options.shortCode Usually, a unique number is tagged to an M-PESA pay bill/till number of the organization
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @return {Promise<Object>} c2bSimulateResponse.
+ */
+async function c2bSimulate({
+  msisdn,
+  amount,
+  billRefNumber,
+  shortCode,
+  proErrorLogging = false,
+}) {
+  /** SIMULATE SHOULD ONLY BE PERFORMED IN SANDBOX MODE, NEVER IN PRODUCTION **/
+  const { accessToken, baseURL } = await generateOAuthToken();
+  if (baseURL === "https://api.safaricom.co.ke") {
+    throw new Error(
+      "Simulation is allowed only in development or sandbox environment!",
+    );
+  }
+  try {
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    const config = {
+      commandId: "CustomerPayBillOnline",
+    };
+    const responseBody = await req.post(`/mpesa/c2b/v1/simulate`, {
+      ShortCode: shortCode,
+      CommandID: config.commandId,
+      Amount: amount,
+      Msisdn: validateFormatPhone(msisdn),
+      BillRefNumber: billRefNumber,
+    });
+    return { c2bSimulateResponse: responseBody.data };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for c2bSimulate has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/c2b/v1/simulate",
+          method: "POST",
+          payload: {
+            msisdn,
+            amount,
+            billRefNumber,
+            shortCode,
+          },
+        },
+        "C2B Simulation transaction error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+export { c2bSimulate };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/fonts/OpenSans-Bold-webfont.eot b/docs/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/docs/fonts/OpenSans-Bold-webfont.eot differ diff --git a/docs/fonts/OpenSans-Bold-webfont.svg b/docs/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/docs/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.woff b/docs/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/docs/fonts/OpenSans-Bold-webfont.woff differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.eot b/docs/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/docs/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.svg b/docs/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/docs/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.woff b/docs/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/docs/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Italic-webfont.eot b/docs/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/docs/fonts/OpenSans-Italic-webfont.eot differ diff --git a/docs/fonts/OpenSans-Italic-webfont.svg b/docs/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/docs/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Italic-webfont.woff b/docs/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/docs/fonts/OpenSans-Italic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Light-webfont.eot b/docs/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/docs/fonts/OpenSans-Light-webfont.eot differ diff --git a/docs/fonts/OpenSans-Light-webfont.svg b/docs/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/docs/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Light-webfont.woff b/docs/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/docs/fonts/OpenSans-Light-webfont.woff differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.eot b/docs/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/docs/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.svg b/docs/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/docs/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-LightItalic-webfont.woff b/docs/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/docs/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Regular-webfont.eot b/docs/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/docs/fonts/OpenSans-Regular-webfont.eot differ diff --git a/docs/fonts/OpenSans-Regular-webfont.svg b/docs/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/docs/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Regular-webfont.woff b/docs/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/docs/fonts/OpenSans-Regular-webfont.woff differ diff --git a/docs/fonts/OpenSans-Semibold-webfont.eot b/docs/fonts/OpenSans-Semibold-webfont.eot new file mode 100644 index 0000000..d8375dd Binary files /dev/null and b/docs/fonts/OpenSans-Semibold-webfont.eot differ diff --git a/docs/fonts/OpenSans-Semibold-webfont.svg b/docs/fonts/OpenSans-Semibold-webfont.svg new file mode 100644 index 0000000..eec4db8 --- /dev/null +++ b/docs/fonts/OpenSans-Semibold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Semibold-webfont.ttf b/docs/fonts/OpenSans-Semibold-webfont.ttf new file mode 100644 index 0000000..b329084 Binary files /dev/null and b/docs/fonts/OpenSans-Semibold-webfont.ttf differ diff --git a/docs/fonts/OpenSans-Semibold-webfont.woff b/docs/fonts/OpenSans-Semibold-webfont.woff new file mode 100644 index 0000000..28d6ade Binary files /dev/null and b/docs/fonts/OpenSans-Semibold-webfont.woff differ diff --git a/docs/fonts/OpenSans-SemiboldItalic-webfont.eot b/docs/fonts/OpenSans-SemiboldItalic-webfont.eot new file mode 100644 index 0000000..0ab1db2 Binary files /dev/null and b/docs/fonts/OpenSans-SemiboldItalic-webfont.eot differ diff --git a/docs/fonts/OpenSans-SemiboldItalic-webfont.svg b/docs/fonts/OpenSans-SemiboldItalic-webfont.svg new file mode 100644 index 0000000..7166ec1 --- /dev/null +++ b/docs/fonts/OpenSans-SemiboldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf b/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf new file mode 100644 index 0000000..d2d6318 Binary files /dev/null and b/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf differ diff --git a/docs/fonts/OpenSans-SemiboldItalic-webfont.woff b/docs/fonts/OpenSans-SemiboldItalic-webfont.woff new file mode 100644 index 0000000..d4dfca4 Binary files /dev/null and b/docs/fonts/OpenSans-SemiboldItalic-webfont.woff differ diff --git a/docs/global.html b/docs/global.html new file mode 100644 index 0000000..f377339 --- /dev/null +++ b/docs/global.html @@ -0,0 +1,1014 @@ + + + + + + Global - Documentation + + + + + + + + + + + + + + + + + +
+ +

Global

+ + + + + + + +
+ +
+ +

+ +

+ + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + +

Members

+ + + +
+

C2BRegister

+ + +

Registers callback validation and confirmation URLs on M-Pesa to receive payment notifications for your paybill/till numbers.

+ + + +
+

Register URL API works hand in hand with Customer to Business (C2B) APIs and allows receiving payment notifications to your paybill. This API enables you to register the callback URLs via which you shall receive notifications for payments to your pay bill/till numbers

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

b2cRequest

+ + +

B2C payments involve a business sending money to an individual. This is a direct transaction from a business shortcode to a consumer's mobile number (MSISDN).

+ + + +
+

B2C API can be used in several scenarios by businesses that require to either make Salary Payments, Cashback payments, Promotional Payments(e.g. betting winning payouts), winnings, financial institutions withdrawal of funds, loan disbursements, etc.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

b2cTopUp

+ + +

Transfers funds from your MMF/Working account to the recipient's utility account for disbursement to a B2C shortcode.

+ + + +
+

This API enables you to load funds to a B2C shortcode directly for disbursement. The transaction moves money from your MMF/Working account to the recipient’s utility account.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

balanceQuery

+ + +

Retrieves the balance of a short code associated with the developer account, supporting B2C, buy goods, and pay bill accounts.

+ + + +
+

The Account Balance API is used to request the account balance of a short code. This can be used for both B2C, buy goods and pay bill accounts.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

businessPaybill

+ + +

Facilitates bill payments from a business account to a paybill number, transferring funds to the recipient’s utility account.

+ + + +
+

This API enables you to pay bills directly from your business account to a pay bill number, or a paybill store. You can use this API to pay on behalf of a consumer/requester. The transaction moves money from your MMF/Working account to the recipient’s utility account.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

c2bSimulate

+ + +

Simulate a transaction from an MSISDN to a business shortcode

+ + + +
+

This function simulates a C2B (Customer to Business) transaction by initiating a payment from an MSISDN to a business shortcode.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

generateQrCode

+ + +

Generates QR codes for customers using My Safaricom app

+ + + +
+

This generates a Dynamic QR which enables Safaricom M-PESA customers who have My Safaricom App or M-PESA app, to scan a QR (Quick Response) code, to capture till number and amount

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

mpesaQuery

+ + +

Check transaction status of a Lipa na M-Pesa payment.

+ + + +
+

Use this API to check the status of a Lipa Na M-Pesa Online Payment.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

mpesaSimulate

+ + +

Sends a payment prompt to the customer's M-PESA registered phone number, requesting them to enter their M-PESA pin to authorize and complete payment.

+ + + +
+

Lipa na M-PESA online API also known as M-PESA express (STK Push/NI push) is a Merchant/Business initiated C2B (Customer to Business) Payment. it enables you to send a payment prompt on the customer's phone (Popularly known as STK Push Prompt) to your customer's M-PESA registered phone number requesting them to enter their M-PESA pin to authorize and complete payment.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

reversals

+ + +

Reverses an M-pesa transaction

+ + + +
+

Reverses a C2B M-Pesa transaction. Once a customer pays and there is a need to reverse the transaction, the organization will use this API to reverse the amount.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

taxRemittance

+ + +

Enables one to remit tax to Kenya Revenue Authority (KRA)

+ + + +
+

This API enables businesses to remit tax to Kenya Revenue Authority (KRA). To use this API, prior integration is required with KRA for tax declaration, payment registration number (PRN) generation, and exchange of other tax-related information.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + +
+

transactionStatus

+ + +

Check the status of a transaction.

+ + + +
+

Enables one to Check the status of an M-pesa transaction, using a unique identifier.

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + +
See:
+
+ +
+ + + +
+ + + + + + + +
+ + + + + + + + + +
+ +
+ + + + +
+ +
+ +
+ Generated by JSDoc 4.0.4 on Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami theme. +
+ + + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..ab53111 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,165 @@ + + + + + + Home - Documentation + + + + + + + + + + + + + + + + +
+
+
+

MPESA-NODE LIBRARY

+

JSDocs guide

+

About

+

+ This documentation is generated using JSDoc and is designed to help + developers accurately map fields to API endpoints. It provides a + clear understanding of which fields are preconfigured by default and + which can be modified based on your requirements. +

+

+ By referring to this guide, you can ensure that you're using the API + correctly and efficiently. Whether you're integrating the library or + extending its functionality, this documentation will serve as a + valuable reference. +

+

Keeping Documentation Up to Date

+

+ If you're contributing to the project, make sure to regenerate the + documentation whenever changes are made to the API. Use the + following commands: +

+

Generate Documentation

+

+ After updating the library, you may + optionally run the commands below to regenerate the + documentation. However, if you prefer, you can leave this task to + the repository maintainer. +

+

npm:npm docs

+

yarn:yarn docs

+

Takeaways

+

+ Keeping the documentation updated ensures that all contributors and + users have access to accurate and up-to-date information. +

+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/mpesa-Query.js.html b/docs/mpesa-Query.js.html new file mode 100644 index 0000000..084d5bc --- /dev/null +++ b/docs/mpesa-Query.js.html @@ -0,0 +1,199 @@ + + + + + + mpesa-Query.js - Documentation + + + + + + + + + + + + + + + + +
+

mpesa-Query.js

+ +
+
+
import {
+  generateMpesaCredentials,
+  generateOAuthToken,
+  logErrorDetails,
+  throwErrorMessages,
+} from "../utils/helpers.js";
+import axios from "axios";
+
+/**
+ * @name mpesaQuery
+ * @description Use this API to check the status of a Lipa Na M-Pesa Online Payment.
+ * @summary Check transaction status of a Lipa na M-Pesa payment.
+ * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressQuery open external link}
+ * @param {Object} options Options for the Lipa Na M-Pesa query API.
+ * @param {string} options.checkoutRequestId Unique identifier for the processed checkout transaction.
+ * @param {number} options.businessShortCode Organization's shortcode (Paybill or Buygoods, 5-7 digits).
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} mpesaQueryResponse.
+ */
+async function mpesaQuery({
+  checkoutRequestId,
+  businessShortCode,
+  proErrorLogging = false,
+}) {
+  const { accessToken, baseURL } = await generateOAuthToken();
+  const { password, timeStamp } = generateMpesaCredentials(businessShortCode);
+  const req = axios.create({
+    baseURL,
+    headers: {
+      Authorization: `Bearer ${accessToken}`,
+      "Content-Type": "application/json",
+    },
+  });
+  try {
+    const responseBody = await req.post("/mpesa/stkpushquery/v1/query", {
+      BusinessShortCode: businessShortCode,
+      Password: password,
+      Timestamp: timeStamp,
+      CheckoutRequestID: checkoutRequestId,
+    });
+
+    return { mpesaQueryResponse: responseBody.data };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for mpesaQuery has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/stkpushquery/v1/query",
+          method: "POST",
+          payload: {
+            businessShortCode,
+            checkoutRequestId,
+          },
+        },
+        "Mpesa Query transaction error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+export { mpesaQuery };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/mpesa-Simulate.js.html b/docs/mpesa-Simulate.js.html new file mode 100644 index 0000000..d0a43d0 --- /dev/null +++ b/docs/mpesa-Simulate.js.html @@ -0,0 +1,247 @@ + + + + + + mpesa-Simulate.js - Documentation + + + + + + + + + + + + + + + + +
+

mpesa-Simulate.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  generateMpesaCredentials,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+  validateFormatPhone,
+  validateUrl
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name mpesaSimulate
+ * @description Lipa na M-PESA online API also known as M-PESA express (STK Push/NI push) is a Merchant/Business initiated C2B (Customer to Business) Payment. it enables you to send a payment prompt on the customer's phone (Popularly known as STK Push Prompt) to your customer's M-PESA registered phone number requesting them to enter their M-PESA pin to authorize and complete payment.
+ * @summary Sends a payment prompt to the customer's M-PESA registered phone number, requesting them to enter their M-PESA pin to authorize and complete payment.
+ * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressSimulate open external link}
+ * @param {Object} options Options for M-Pesa express API.
+ * @param {string} options.partyA Sender's Safaricom mobile number (M-PESA registered).
+ * @param {string} options.phoneNumber Mobile number to receive the STK Pin Prompt (can be same as partyA).
+ * @param {number} options.amount Transaction amount.
+ * @param {string} options.transactionType "CustomerPayBillOnline" for PayBill and "CustomerBuyGoodsOnline" for Till Numbers.
+ * @param {string} options.callbackURL Secure URL for receiving notifications from M-Pesa API.
+ * @param {string} options.transactionDesc Information to be associated with the transaction.
+ * @param {string} options.accountRef Alphanumeric account reference (up to 12 characters) shown in the STK Pin Prompt (Org name).
+ * @param {number} options.partyB 5 to 6-digit number of the receiving organization.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} mpesaSimulateResponse and (optional) conditionalCallbackData.
+ */
+async function mpesaSimulate({
+                               partyA,
+                               phoneNumber,
+                               amount,
+                               callbackURL,
+                               accountRef,
+                               partyB,
+                               transactionType,
+  transactionDesc,
+                               proErrorLogging = false
+                             }) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleMpesaSimulateCallbacks') was not called. Ignore if handling manually.\x1b[0m"
+    );
+  }
+  try {
+    validateUrl(callbackURL, "callbackURL");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const { password, timeStamp } = generateMpesaCredentials(partyB);
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json"
+      }
+
+    });
+    const responseBody = await req.post("/mpesa/stkpush/v1/processrequest", {
+      BusinessShortCode: partyB,
+      Password: password,
+      Timestamp: timeStamp,
+      Amount: amount,
+      PartyA: validateFormatPhone(partyA),
+      PartyB: partyB,
+      PhoneNumber: validateFormatPhone(phoneNumber),
+      CallBackURL: callbackURL,
+      AccountReference: accountRef,
+      TransactionDesc: transactionDesc,
+      TransactionType: transactionType
+    });
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized, true);
+    return {
+      mpesaSimulateResponse: responseBody.data,
+      conditionalCallbackData
+    };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for mpesaSimulate has been initialized"
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/stkpush/v1/processrequest",
+          method: "POST",
+          payload: {
+            partyA,
+            phoneNumber,
+            amount,
+            callbackURL,
+            accountRef,
+            partyB,
+            transactionDesc
+          }
+        },
+        "Mpesa Simulate transaction error details:"
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleMpesaSimulateCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "mpesaSimulate");
+};
+export { mpesaSimulate, handleMpesaSimulateCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/qr-Generate.js.html b/docs/qr-Generate.js.html new file mode 100644 index 0000000..3792c23 --- /dev/null +++ b/docs/qr-Generate.js.html @@ -0,0 +1,222 @@ + + + + + + qr-Generate.js - Documentation + + + + + + + + + + + + + + + + +
+

qr-Generate.js

+ +
+
+
import axios from "axios";
+import {
+  generateOAuthToken,
+  logErrorDetails,
+  throwErrorMessages,
+} from "../utils/helpers.js";
+import { trxCodeTypes } from "../utils/constants.js";
+
+/**
+ * @name generateQrCode
+ * @description This generates a Dynamic QR which enables Safaricom M-PESA customers who have My Safaricom App or M-PESA app, to scan a QR (Quick Response) code, to capture till number and amount
+ * @summary Generates QR codes for customers using My Safaricom app
+ * @see {@link https://developer.safaricom.co.ke/APIs/DynamicQRCode open external link}
+ * @param {Object} options Options for the QR code generation request.
+ * @param {string} options.merchantName - The name of the company or M-Pesa merchant requesting the QR code.
+ * @param {string} options.refNo A unique reference number for the transaction.
+ * @param {number} options.amount The total amount for the sale or transaction.
+ * @param {string} options.trxCode Transaction type. Supported types: BG, WA, PB, SM, SB.
+ * @param {string} options.cpi Credit Party Identifier (e.g., mobile number, business number).
+ * @param {string} options.size Size of the QR code image in pixels. QR code image will always be square.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} generateQrcodeResponse.
+ */
+async function generateQrCode({
+  merchantName,
+  refNo,
+  amount,
+  trxCode,
+  cpi,
+  size,
+  proErrorLogging = false,
+}) {
+  /**
+   * @param {string} validTrxCodes - Only support: buy goods: "BG" - withdraw agent till: "WA" - paybill business number: "PB" - send money msisdn: "SM" and end to business msisdn: "SB"
+   */
+  const validTrxCodes = Object.values(trxCodeTypes);
+  if (!validTrxCodes.includes(trxCode)) {
+    throw new Error(
+      `Invalid trxCode provided. Must be one of: ${validTrxCodes.join(", ")}`,
+    );
+  }
+  try {
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    const responseBody = await req.post("/mpesa/qrcode/v1/generate", {
+      MerchantName: merchantName,
+      RefNo: refNo,
+      Amount: amount,
+      TrxCode: trxCode,
+      CPI: cpi,
+      Size: size,
+    });
+    return { generateQrcodeResponse: responseBody.data };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for generateQrcode has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/qrcode/v1/generate",
+          method: "POST",
+          payload: {
+            merchantName,
+            refNo,
+            amount,
+            trxCode,
+            cpi,
+            size,
+          },
+        },
+        "QR code generation error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+export { generateQrCode };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/reversals.js.html b/docs/reversals.js.html new file mode 100644 index 0000000..c16f83a --- /dev/null +++ b/docs/reversals.js.html @@ -0,0 +1,249 @@ + + + + + + reversals.js - Documentation + + + + + + + + + + + + + + + + +
+

reversals.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  encryptSecurityCredential,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+  validateUrl,
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name reversals
+ * @description Reverses a C2B M-Pesa transaction. Once a customer pays and there is a need to reverse the transaction, the organization will use this API to reverse the amount.
+ * @summary Reverses an M-pesa transaction
+ * @see {@link https://developer.safaricom.co.ke/APIs/Reversal open external link}
+ * @param {Object} options Options for the reversal API.
+ * @param {string} options.transactionId Transaction ID for reversal (e.g., LKXXXX1234).
+ * @param {number} options.amount Amount to be reversed.
+ * @param {string} options.QueueTimeOutURL URL for timeout transaction details.
+ * @param {string} options.resultURL URL for transaction details.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {string} options.occasion Information to be associated with the transaction.
+ * @param {number} options.receiverParty Organization receiving the transaction.
+ * @param {string} options.initiator Name of the initiator of the request.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} reversalsResponse and (optional) conditionalCallbackData.
+ */
+async function reversals({
+  transactionId,
+  amount,
+  QueueTimeOutURL,
+  resultURL,
+  receiverParty,
+  initiator,
+  remarks,
+  occasion,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info("\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleReversalCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "timeoutUrl");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    // default configurations
+    const config = {
+      receiverIdType: "11",
+      commandId: "TransactionReversal",
+    };
+    const responseBody = await req.post("/mpesa/reversal/v1/request", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      TransactionID: transactionId,
+      Amount: amount,
+      ReceiverParty: receiverParty,
+      RecieverIdentifierType: config.receiverIdType,
+      ResultURL: resultURL,
+      QueueTimeOutURL: QueueTimeOutURL,
+      Remarks: remarks,
+      Occasion: occasion,
+    });
+
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+
+    return { reversalsResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for reversals has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/reversal/v1/request",
+          method: "POST",
+          payload: {
+            transactionId,
+            amount,
+            QueueTimeOutURL,
+            resultURL,
+            receiverParty,
+            initiator,
+            remarks,
+            occasion
+          },
+        },
+        "Transaction reversal error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+const handleReversalCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "reversals");
+};
+
+export { reversals, handleReversalCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js new file mode 100644 index 0000000..20b6b09 --- /dev/null +++ b/docs/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(function () { + var source = document.getElementsByClassName("prettyprint source linenums"); + var i = 0; + var lineNumber = 0; + var lineId; + var lines; + var totalLines; + var anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName("li"); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = "line" + lineNumber; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += " selected"; + } + } + } +})(); diff --git a/docs/scripts/prettify/Apache-License-2.0.txt b/docs/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/docs/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js new file mode 100644 index 0000000..1918eab --- /dev/null +++ b/docs/scripts/prettify/lang-css.js @@ -0,0 +1,36 @@ +PR.registerLangHandler( + PR.createSimpleLexer( + [["pln", /^[\t\n\f\r ]+/, null, " \t\r\n "]], + [ + ["str", /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], + ["str", /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], + ["lang-css-str", /^url\(([^"')]*)\)/i], + [ + "kwd", + /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, + null, + ], + [ + "lang-css-kw", + /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i, + ], + ["com", /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], + ["com", /^(?:<\!--|--\>)/], + ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], + ["lit", /^#[\da-f]{3,6}/i], + ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], + ["pun", /^[^\s\w"']+/], + ], + ), + ["css"], +); +PR.registerLangHandler( + PR.createSimpleLexer( + [], + [["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]], + ), + ["css-kw"], +); +PR.registerLangHandler(PR.createSimpleLexer([], [["str", /^[^"')]+/]]), [ + "css-str", +]); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js new file mode 100644 index 0000000..d08f9d8 --- /dev/null +++ b/docs/scripts/prettify/prettify.js @@ -0,0 +1,740 @@ +var q = null; +window.PR_SHOULD_USE_CONTINUATION = !0; +(function () { + function L(a) { + function m(a) { + var f = a.charCodeAt(0); + if (f !== 92) return f; + var b = a.charAt(1); + return (f = r[b]) + ? f + : "0" <= b && b <= "7" + ? parseInt(a.substring(1), 8) + : b === "u" || b === "x" + ? parseInt(a.substring(2), 16) + : a.charCodeAt(1); + } + function e(a) { + if (a < 32) return (a < 16 ? "\\x0" : "\\x") + a.toString(16); + a = String.fromCharCode(a); + if (a === "\\" || a === "-" || a === "[" || a === "]") a = "\\" + a; + return a; + } + function h(a) { + for ( + var f = a + .substring(1, a.length - 1) + .match( + /\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g, + ), + a = [], + b = [], + o = f[0] === "^", + c = o ? 1 : 0, + i = f.length; + c < i; + ++c + ) { + var j = f[c]; + if (/\\[bdsw]/i.test(j)) a.push(j); + else { + var j = m(j), + d; + c + 2 < i && "-" === f[c + 1] + ? ((d = m(f[c + 2])), (c += 2)) + : (d = j); + b.push([j, d]); + d < 65 || + j > 122 || + (d < 65 || + j > 90 || + b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), + d < 97 || + j > 122 || + b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])); + } + } + b.sort(function (a, f) { + return a[0] - f[0] || f[1] - a[1]; + }); + f = []; + j = [NaN, NaN]; + for (c = 0; c < b.length; ++c) + (i = b[c]), + i[0] <= j[1] + 1 ? (j[1] = Math.max(j[1], i[1])) : f.push((j = i)); + b = ["["]; + o && b.push("^"); + b.push.apply(b, a); + for (c = 0; c < f.length; ++c) + (i = f[c]), + b.push(e(i[0])), + i[1] > i[0] && (i[1] + 1 > i[0] && b.push("-"), b.push(e(i[1]))); + b.push("]"); + return b.join(""); + } + function y(a) { + for ( + var f = a.source.match( + /\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g, + ), + b = f.length, + d = [], + c = 0, + i = 0; + c < b; + ++c + ) { + var j = f[c]; + j === "(" + ? ++i + : "\\" === j.charAt(0) && + (j = +j.substring(1)) && + j <= i && + (d[j] = -1); + } + for (c = 1; c < d.length; ++c) -1 === d[c] && (d[c] = ++t); + for (i = c = 0; c < b; ++c) + (j = f[c]), + j === "(" + ? (++i, d[i] === void 0 && (f[c] = "(?:")) + : "\\" === j.charAt(0) && + (j = +j.substring(1)) && + j <= i && + (f[c] = "\\" + d[i]); + for (i = c = 0; c < b; ++c) + "^" === f[c] && "^" !== f[c + 1] && (f[c] = ""); + if (a.ignoreCase && s) + for (c = 0; c < b; ++c) + (j = f[c]), + (a = j.charAt(0)), + j.length >= 2 && a === "[" + ? (f[c] = h(j)) + : a !== "\\" && + (f[c] = j.replace(/[A-Za-z]/g, function (a) { + a = a.charCodeAt(0); + return "[" + String.fromCharCode(a & -33, a | 32) + "]"; + })); + return f.join(""); + } + for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { + var g = a[p]; + if (g.ignoreCase) l = !0; + else if ( + /[a-z]/i.test( + g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ""), + ) + ) { + s = !0; + l = !1; + break; + } + } + for ( + var r = { b: 8, t: 9, n: 10, v: 11, f: 12, r: 13 }, + n = [], + p = 0, + d = a.length; + p < d; + ++p + ) { + g = a[p]; + if (g.global || g.multiline) throw Error("" + g); + n.push("(?:" + y(g) + ")"); + } + return RegExp(n.join("|"), l ? "gi" : "g"); + } + function M(a) { + function m(a) { + switch (a.nodeType) { + case 1: + if (e.test(a.className)) break; + for (var g = a.firstChild; g; g = g.nextSibling) m(g); + g = a.nodeName; + if ("BR" === g || "LI" === g) + (h[s] = "\n"), (t[s << 1] = y++), (t[(s++ << 1) | 1] = a); + break; + case 3: + case 4: + (g = a.nodeValue), + g.length && + ((g = p + ? g.replace(/\r\n?/g, "\n") + : g.replace(/[\t\n\r ]+/g, " ")), + (h[s] = g), + (t[s << 1] = y), + (y += g.length), + (t[(s++ << 1) | 1] = a)); + } + } + var e = /(?:^|\s)nocode(?:\s|$)/, + h = [], + y = 0, + t = [], + s = 0, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && + (l = document.defaultView + .getComputedStyle(a, q) + .getPropertyValue("white-space")); + var p = l && "pre" === l.substring(0, 3); + m(a); + return { a: h.join("").replace(/\n$/, ""), c: t }; + } + function B(a, m, e, h) { + m && ((a = { a: m, d: a }), e(a), h.push.apply(h, a.e)); + } + function x(a, m) { + function e(a) { + for ( + var l = a.d, + p = [l, "pln"], + d = 0, + g = a.a.match(y) || [], + r = {}, + n = 0, + z = g.length; + n < z; + ++n + ) { + var f = g[n], + b = r[f], + o = void 0, + c; + if (typeof b === "string") c = !1; + else { + var i = h[f.charAt(0)]; + if (i) (o = f.match(i[1])), (b = i[0]); + else { + for (c = 0; c < t; ++c) + if (((i = m[c]), (o = f.match(i[1])))) { + b = i[0]; + break; + } + o || (b = "pln"); + } + if ( + (c = b.length >= 5 && "lang-" === b.substring(0, 5)) && + !(o && typeof o[1] === "string") + ) + (c = !1), (b = "src"); + c || (r[f] = b); + } + i = d; + d += f.length; + if (c) { + c = o[1]; + var j = f.indexOf(c), + k = j + c.length; + o[2] && ((k = f.length - o[2].length), (j = k - c.length)); + b = b.substring(5); + B(l + i, f.substring(0, j), e, p); + B(l + i + j, c, C(b, c), p); + B(l + i + k, f.substring(k), e, p); + } else p.push(l + i, b); + } + a.e = p; + } + var h = {}, + y; + (function () { + for ( + var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; + d < g; + ++d + ) { + var r = e[d], + n = r[3]; + if (n) for (var k = n.length; --k >= 0; ) h[n.charAt(k)] = r; + r = r[1]; + n = "" + r; + p.hasOwnProperty(n) || (l.push(r), (p[n] = q)); + } + l.push(/[\S\s]/); + y = L(l); + })(); + var t = m.length; + return e; + } + function u(a) { + var m = [], + e = []; + a.tripleQuotedStrings + ? m.push([ + "str", + /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, + q, + "'\"", + ]) + : a.multiLineStrings + ? m.push([ + "str", + /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, + q, + "'\"`", + ]) + : m.push([ + "str", + /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, + q, + "\"'", + ]); + a.verbatimStrings && e.push(["str", /^@"(?:[^"]|"")*(?:"|$)/, q]); + var h = a.hashComments; + h && + (a.cStyleComments + ? (h > 1 + ? m.push(["com", /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, "#"]) + : m.push([ + "com", + /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, + q, + "#", + ]), + e.push([ + "str", + /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, + q, + ])) + : m.push(["com", /^#[^\n\r]*/, q, "#"])); + a.cStyleComments && + (e.push(["com", /^\/\/[^\n\r]*/, q]), + e.push(["com", /^\/\*[\S\s]*?(?:\*\/|$)/, q])); + a.regexLiterals && + e.push([ + "lang-regex", + /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/, + ]); + (h = a.types) && e.push(["typ", h]); + a = ("" + a.keywords).replace(/^ | $/g, ""); + a.length && + e.push(["kwd", RegExp("^(?:" + a.replace(/[\s,]+/g, "|") + ")\\b"), q]); + m.push(["pln", /^\s+/, q, " \r\n\t\xa0"]); + e.push( + ["lit", /^@[$_a-z][\w$@]*/i, q], + ["typ", /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], + ["pln", /^[$_a-z][\w$@]*/i, q], + [ + "lit", + /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, + q, + "0123456789", + ], + ["pln", /^\\[\S\s]?/, q], + ["pun", /^.[^\s\w"-$'./@\\`]*/, q], + ); + return x(m, e); + } + function D(a, m) { + function e(a) { + switch (a.nodeType) { + case 1: + if (k.test(a.className)) break; + if ("BR" === a.nodeName) + h(a), a.parentNode && a.parentNode.removeChild(a); + else for (a = a.firstChild; a; a = a.nextSibling) e(a); + break; + case 3: + case 4: + if (p) { + var b = a.nodeValue, + d = b.match(t); + if (d) { + var c = b.substring(0, d.index); + a.nodeValue = c; + (b = b.substring(d.index + d[0].length)) && + a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); + h(a); + c || a.parentNode.removeChild(a); + } + } + } + } + function h(a) { + function b(a, d) { + var e = d ? a.cloneNode(!1) : a, + f = a.parentNode; + if (f) { + var f = b(f, 1), + g = a.nextSibling; + f.appendChild(e); + for (var h = g; h; h = g) (g = h.nextSibling), f.appendChild(h); + } + return e; + } + for (; !a.nextSibling; ) if (((a = a.parentNode), !a)) return; + for ( + var a = b(a.nextSibling, 0), e; + (e = a.parentNode) && e.nodeType === 1; + + ) + a = e; + d.push(a); + } + var k = /(?:^|\s)nocode(?:\s|$)/, + t = /\r\n?|\n/, + s = a.ownerDocument, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && + (l = s.defaultView + .getComputedStyle(a, q) + .getPropertyValue("white-space")); + var p = l && "pre" === l.substring(0, 3); + for (l = s.createElement("LI"); a.firstChild; ) l.appendChild(a.firstChild); + for (var d = [l], g = 0; g < d.length; ++g) e(d[g]); + m === (m | 0) && d[0].setAttribute("value", m); + var r = s.createElement("OL"); + r.className = "linenums"; + for (var n = Math.max(0, (m - 1) | 0) || 0, g = 0, z = d.length; g < z; ++g) + (l = d[g]), + (l.className = "L" + ((g + n) % 10)), + l.firstChild || l.appendChild(s.createTextNode("\xa0")), + r.appendChild(l); + a.appendChild(r); + } + function k(a, m) { + for (var e = m.length; --e >= 0; ) { + var h = m[e]; + A.hasOwnProperty(h) + ? window.console && + console.warn("cannot override language handler %s", h) + : (A[h] = a); + } + } + function C(a, m) { + if (!a || !A.hasOwnProperty(a)) + a = /^\s*= o && (h += 2); + e >= c && (a += 2); + } + } catch (w) { + "console" in window && console.log(w && w.stack ? w.stack : w); + } + } + var v = ["break,continue,do,else,for,if,return,while"], + w = [ + [ + v, + "auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile", + ], + "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof", + ], + F = [ + w, + "alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where", + ], + G = [ + w, + "abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient", + ], + H = [ + G, + "as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var", + ], + w = [ + w, + "debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN", + ], + I = [ + v, + "and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None", + ], + J = [ + v, + "alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END", + ], + v = [v, "case,done,elif,esac,eval,fi,function,in,local,set,then,until"], + K = + /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, + N = /\S/, + O = u({ + keywords: [ + F, + H, + w, + "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END" + + I, + J, + v, + ], + hashComments: !0, + cStyleComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + A = {}; + k(O, ["default-code"]); + k( + x( + [], + [ + ["pln", /^[^]*(?:>|$)/], + ["com", /^<\!--[\S\s]*?(?:--\>|$)/], + ["lang-", /^<\?([\S\s]+?)(?:\?>|$)/], + ["lang-", /^<%([\S\s]+?)(?:%>|$)/], + ["pun", /^(?:<[%?]|[%?]>)/], + ["lang-", /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], + ["lang-js", /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], + ["lang-css", /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], + ["lang-in.tag", /^(<\/?[a-z][^<>]*>)/i], + ], + ), + ["default-markup", "htm", "html", "mxml", "xhtml", "xml", "xsl"], + ); + k( + x( + [ + ["pln", /^\s+/, q, " \t\r\n"], + ["atv", /^(?:"[^"]*"?|'[^']*'?)/, q, "\"'"], + ], + [ + ["tag", /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], + ["atn", /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], + ["lang-uq.val", /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], + ["pun", /^[/<->]+/], + ["lang-js", /^on\w+\s*=\s*"([^"]+)"/i], + ["lang-js", /^on\w+\s*=\s*'([^']+)'/i], + ["lang-js", /^on\w+\s*=\s*([^\s"'>]+)/i], + ["lang-css", /^style\s*=\s*"([^"]+)"/i], + ["lang-css", /^style\s*=\s*'([^']+)'/i], + ["lang-css", /^style\s*=\s*([^\s"'>]+)/i], + ], + ), + ["in.tag"], + ); + k(x([], [["atv", /^[\S\s]+/]]), ["uq.val"]); + k(u({ keywords: F, hashComments: !0, cStyleComments: !0, types: K }), [ + "c", + "cc", + "cpp", + "cxx", + "cyc", + "m", + ]); + k(u({ keywords: "null,true,false" }), ["json"]); + k( + u({ + keywords: H, + hashComments: !0, + cStyleComments: !0, + verbatimStrings: !0, + types: K, + }), + ["cs"], + ); + k(u({ keywords: G, cStyleComments: !0 }), ["java"]); + k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), [ + "bsh", + "csh", + "sh", + ]); + k( + u({ + keywords: I, + hashComments: !0, + multiLineStrings: !0, + tripleQuotedStrings: !0, + }), + ["cv", "py"], + ); + k( + u({ + keywords: + "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END", + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + ["perl", "pl", "pm"], + ); + k( + u({ + keywords: J, + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + ["rb"], + ); + k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ["js"]); + k( + u({ + keywords: + "all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", + hashComments: 3, + cStyleComments: !0, + multilineStrings: !0, + tripleQuotedStrings: !0, + regexLiterals: !0, + }), + ["coffee"], + ); + k(x([], [["str", /^[\S\s]+/]]), ["regex"]); + window.prettyPrintOne = function (a, m, e) { + var h = document.createElement("PRE"); + h.innerHTML = a; + e && D(h, e); + E({ g: m, i: e, h: h }); + return h.innerHTML; + }; + window.prettyPrint = function (a) { + function m() { + for ( + var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; + p < h.length && l.now() < e; + p++ + ) { + var n = h[p], + k = n.className; + if (k.indexOf("prettyprint") >= 0) { + var k = k.match(g), + f, + b; + if ((b = !k)) { + b = n; + for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) + var i = c.nodeType, + o = + i === 1 + ? o + ? b + : c + : i === 3 + ? N.test(c.nodeValue) + ? b + : o + : o; + b = (f = o === b ? void 0 : o) && "CODE" === f.tagName; + } + b && (k = f.className.match(g)); + k && (k = k[1]); + b = !1; + for (o = n.parentNode; o; o = o.parentNode) + if ( + (o.tagName === "pre" || + o.tagName === "code" || + o.tagName === "xmp") && + o.className && + o.className.indexOf("prettyprint") >= 0 + ) { + b = !0; + break; + } + b || + ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) + ? b[1] && b[1].length + ? +b[1] + : !0 + : !1) && D(n, b), + (d = { g: k, h: n, i: b }), + E(d)); + } + } + p < h.length ? setTimeout(m, 250) : a && a(); + } + for ( + var e = [ + document.getElementsByTagName("pre"), + document.getElementsByTagName("code"), + document.getElementsByTagName("xmp"), + ], + h = [], + k = 0; + k < e.length; + ++k + ) + for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]); + var e = q, + l = Date; + l.now || + (l = { + now: function () { + return +new Date(); + }, + }); + var p = 0, + d, + g = /\blang(?:uage)?-([\w.]+)(?!\S)/; + m(); + }; + window.PR = { + createSimpleLexer: x, + registerLangHandler: k, + sourceDecorator: u, + PR_ATTRIB_NAME: "atn", + PR_ATTRIB_VALUE: "atv", + PR_COMMENT: "com", + PR_DECLARATION: "dec", + PR_KEYWORD: "kwd", + PR_LITERAL: "lit", + PR_NOCODE: "nocode", + PR_PLAIN: "pln", + PR_PUNCTUATION: "pun", + PR_SOURCE: "src", + PR_STRING: "str", + PR_TAG: "tag", + PR_TYPE: "typ", + }; +})(); diff --git a/docs/styles/jsdoc-default.css b/docs/styles/jsdoc-default.css new file mode 100644 index 0000000..7432b3b --- /dev/null +++ b/docs/styles/jsdoc-default.css @@ -0,0 +1,733 @@ +@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,500i,500,600,600i|Roboto); + +* { + box-sizing: border-box; +} + +html, +body { + height: 100%; + width: 100%; +} + +body { + color: #4d4e53; + background-color: white; + margin: 0 auto; + padding: 0; + font-family: "Source Sans Pro", Helvetica, sans-serif; + font-size: 16px; + line-height: 160%; +} + +a, +a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +p, +ul, +ol, +blockquote { + margin-bottom: 1em; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Roboto", sans-serif; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #000; + font-weight: 400; + margin: 0; +} + +h1 { + font-weight: 300; + font-size: 48px; + margin: 1em 0 0.5em; +} + +h1.page-title { + margin-bottom: 10px; + font-size: 34px; + font-weight: 300; + border-bottom: solid 2px #ddd; + padding: 0.5em 0 0.5em; + margin-top: 0; +} + +h2 { + font-size: 32px; + margin: 1.2em 0 0.8em; + font-weight: bold; +} + +h3 { + /* margin-top: 1em; */ + /* margin-bottom: 16px; */ + /* font-weight: bold; */ + padding: 0; + margin: 1em 0 0.6em; + font-size: 28px; + /* border-bottom: 1px solid #eee; */ + /* padding-bottom: 15px; */ +} + +h4 { + font-size: 18px; + margin: 1em 0 0.2em; + color: #4d4e53; + /* border-bottom: 1px solid #eee; */ + padding-bottom: 8px; +} + +h5, +.container-overview .subsection-title { + font-size: 120%; + /* letter-spacing: -0.01em; */ + margin: 20px 0 5px; +} + +h6 { + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +tt, +code, +kbd, +samp { + font-family: Consolas, Monaco, "Andale Mono", monospace; + background: #f4f4f4; + padding: 1px 5px; + border-radius: 5px; + font-size: 14px; +} + +blockquote { + display: block; + border-left: 4px solid #eee; + margin: 0; + padding-left: 1em; + color: #888; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +/** Container **/ +#main { + float: right; + min-width: 360px; + width: calc(100% - 250px); + padding: 0 30px 20px 30px; +} + +header { + display: block; +} + +section { + display: block; + background-color: #fff; + padding: 0; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +/** Readme **/ + +.readme { + font-size: 16px; +} + +.readme h1, +.readme h2, +.readme h3, +.readme h4, +.readme h5 { + margin-top: 1em; + margin-bottom: 16px; + font-weight: bold; + padding: 0; +} + +.readme h1 { + font-size: 2em; + padding-bottom: 0.3em; +} + +.readme h2 { + font-size: 1.75em; + padding-bottom: 0.3em; +} + +.readme h3 { + font-size: 1.5em; + background-color: transparent; +} + +.readme h4 { + font-size: 1.25em; +} + +.readme h5 { + font-size: 1em; +} + +.readme img { + max-width: 100%; +} + +.readme ul, +.readme ol { + padding-left: 2em; +} + +.readme pre > code { + font-size: 0.85em; +} + +.readme table { + margin-bottom: 1em; + border-collapse: collapse; + border-spacing: 0; +} + +.readme table tr { + background-color: #fff; + border-top: 1px solid #ccc; +} + +.readme table th, +.readme table td { + padding: 6px 13px; + border: 1px solid #ddd; +} + +.readme table tr:nth-child(2n) { + background-color: #f8f8f8; +} + +/** Nav **/ +nav { + float: left; + display: block; + width: 250px; + background: #fff; + overflow: auto; + position: fixed; + height: 100%; + padding: 10px; + border-right: 1px solid #eee; + /* box-shadow: 0 0 3px rgba(0,0,0,0.1); */ +} + +nav li { + list-style: none; + padding: 0; + margin: 0; +} + +.nav-heading { + margin-top: 10px; + font-weight: bold; +} + +.nav-heading a { + color: #888; + font-size: 14px; + display: inline-block; +} + +.nav-item-type { + /* margin-left: 5px; */ + width: 18px; + height: 18px; + display: inline-block; + text-align: center; + border-radius: 0.2em; + margin-right: 5px; + font-weight: bold; + line-height: 20px; + font-size: 13px; +} + +.type-function { + background: #b3e5fc; + color: #0288d1; +} + +.type-class { + background: #d1c4e9; + color: #4527a0; +} + +.type-member { + background: #c8e6c9; + color: #388e3c; +} + +.type-module { + background: #e1bee7; + color: #7b1fa2; +} + +/** Footer **/ +footer { + color: hsl(0, 0%, 28%); + margin-left: 250px; + display: block; + padding: 30px; + font-style: italic; + font-size: 90%; + border-top: 1px solid #eee; +} + +.ancestors { + color: #999; +} + +.ancestors a { + color: #999 !important; + text-decoration: none; +} + +.clear { + clear: both; +} + +.important { + font-weight: bold; + color: #950b02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, +.signature { + font-family: Consolas, Monaco, "Andale Mono", monospace; +} + +.details { + margin-top: 14px; + border-left: 2px solid #ddd; + line-height: 30px; +} + +.details dt { + width: 120px; + float: left; + padding-left: 10px; +} + +.details dd { + margin-left: 70px; +} + +.details ul { + margin: 0; +} + +.details ul { + list-style-type: none; +} + +.details li { + margin-left: 30px; +} + +.details pre.prettyprint { + margin: 0; +} + +.details .object-value { + padding-top: 0; +} + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption { + font-style: italic; + font-size: 107%; + margin: 0; +} + +.prettyprint { + font-size: 13px; + border: 1px solid #ddd; + border-radius: 3px; + box-shadow: 0 1px 3px hsla(0, 0%, 0%, 0.05); + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.prettyprint code { + font-size: 12px; + line-height: 18px; + display: block; + background-color: #fff; + color: #4d4e53; +} + +.prettyprint code:empty:before { + content: ""; +} + +.prettyprint > code { + padding: 15px; +} + +.prettyprint .linenums code { + padding: 0 15px; +} + +.prettyprint .linenums li:first-of-type code { + padding-top: 15px; +} + +.prettyprint code span.line { + display: inline-block; +} + +.prettyprint.linenums { + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol { + padding-left: 0; +} + +.prettyprint.linenums li { + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * { + background-color: lightyellow; +} + +.prettyprint.linenums li * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params, +.props { + border-spacing: 0; + border: 1px solid #ddd; + border-collapse: collapse; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + width: 100%; + font-size: 14px; + /* margin-left: 15px; */ +} + +.params .name, +.props .name, +.name code { + color: #4d4e53; + font-family: Consolas, Monaco, "Andale Mono", monospace; + font-size: 100%; +} + +.params td, +.params th, +.props td, +.props th { + margin: 0px; + text-align: left; + vertical-align: top; + padding: 10px; + display: table-cell; +} + +.params td { + border-top: 1px solid #eee; +} + +.params thead tr, +.props thead tr { + background-color: #fff; + font-weight: bold; +} + +.params .params thead tr, +.props .props thead tr { + background-color: #fff; + font-weight: bold; +} + +.params td.description > p:first-child, +.props td.description > p:first-child { + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +dl.param-type { + /* border-bottom: 1px solid hsl(0, 0%, 87%); */ + margin: 0; + padding: 0; + font-size: 16px; +} + +.param-type dt, +.param-type dd { + display: inline-block; +} + +.param-type dd { + font-family: Consolas, Monaco, "Andale Mono", monospace; + display: inline-block; + padding: 0; + margin: 0; + font-size: 14px; +} + +.disabled { + color: #454545; +} + +/* navicon button */ +.navicon-button { + display: none; + position: relative; + padding: 2.0625rem 1.5rem; + transition: 0.25s; + cursor: pointer; + user-select: none; + opacity: 0.8; +} +.navicon-button .navicon:before, +.navicon-button .navicon:after { + transition: 0.25s; +} +.navicon-button:hover { + transition: 0.5s; + opacity: 1; +} +.navicon-button:hover .navicon:before, +.navicon-button:hover .navicon:after { + transition: 0.25s; +} +.navicon-button:hover .navicon:before { + top: 0.825rem; +} +.navicon-button:hover .navicon:after { + top: -0.825rem; +} + +/* navicon */ +.navicon { + position: relative; + width: 2.5em; + height: 0.3125rem; + background: #000; + transition: 0.3s; + border-radius: 2.5rem; +} +.navicon:before, +.navicon:after { + display: block; + content: ""; + height: 0.3125rem; + width: 2.5rem; + background: #000; + position: absolute; + z-index: -1; + transition: 0.3s 0.25s; + border-radius: 1rem; +} +.navicon:before { + top: 0.625rem; +} +.navicon:after { + top: -0.625rem; +} + +/* open */ +.nav-trigger:checked + label:not(.steps) .navicon:before, +.nav-trigger:checked + label:not(.steps) .navicon:after { + top: 0 !important; +} + +.nav-trigger:checked + label .navicon:before, +.nav-trigger:checked + label .navicon:after { + transition: 0.5s; +} + +/* Minus */ +.nav-trigger:checked + label { + transform: scale(0.75); +} + +/* × and + */ +.nav-trigger:checked + label.plus .navicon, +.nav-trigger:checked + label.x .navicon { + background: transparent; +} + +.nav-trigger:checked + label.plus .navicon:before, +.nav-trigger:checked + label.x .navicon:before { + transform: rotate(-45deg); + background: #fff; +} + +.nav-trigger:checked + label.plus .navicon:after, +.nav-trigger:checked + label.x .navicon:after { + transform: rotate(45deg); + background: #fff; +} + +.nav-trigger:checked + label.plus { + transform: scale(0.75) rotate(45deg); +} + +.nav-trigger:checked ~ nav { + left: 0 !important; +} + +.nav-trigger:checked ~ .overlay { + display: block; +} + +.nav-trigger { + position: fixed; + top: 0; + clip: rect(0, 0, 0, 0); +} + +.overlay { + display: none; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + background: hsla(0, 0%, 0%, 0.5); + z-index: 1; +} + +.section-method { + margin-bottom: 30px; + padding-bottom: 30px; + border-bottom: 1px solid #eee; +} + +@media only screen and (min-width: 320px) and (max-width: 680px) { + body { + overflow-x: hidden; + } + + nav { + background: #fff; + width: 250px; + height: 100%; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: -250px; + z-index: 3; + padding: 0 10px; + transition: left 0.2s; + } + + .navicon-button { + display: inline-block; + position: fixed; + top: 1.5em; + right: 0; + z-index: 2; + } + + #main { + width: 100%; + min-width: 360px; + } + + #main h1.page-title { + margin: 1em 0; + } + + #main section { + padding: 0; + } + + footer { + margin-left: 0; + } +} + +@media only print { + nav { + display: none; + } + + #main { + float: none; + width: 100%; + } +} diff --git a/docs/styles/prettify-jsdoc.css b/docs/styles/prettify-jsdoc.css new file mode 100644 index 0000000..834a866 --- /dev/null +++ b/docs/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: hsl(104, 100%, 24%); + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/docs/styles/prettify-tomorrow.css b/docs/styles/prettify-tomorrow.css new file mode 100644 index 0000000..921a383 --- /dev/null +++ b/docs/styles/prettify-tomorrow.css @@ -0,0 +1,163 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; +} + +@media screen { + /* string content */ + .str { + color: hsl(104, 100%, 24%); + } + + /* a keyword */ + .kwd { + color: hsl(240, 100%, 50%); + } + + /* a comment */ + .com { + color: hsl(0, 0%, 60%); + } + + /* a type name */ + .typ { + color: hsl(240, 100%, 32%); + } + + /* a literal value */ + .lit { + color: hsl(240, 100%, 40%); + } + + /* punctuation */ + .pun { + color: #000000; + } + + /* lisp open bracket */ + .opn { + color: #000000; + } + + /* lisp close bracket */ + .clo { + color: #000000; + } + + /* a markup tag name */ + .tag { + color: #c82829; + } + + /* a markup attribute name */ + .atn { + color: #f5871f; + } + + /* a markup attribute value */ + .atv { + color: #3e999f; + } + + /* a declaration */ + .dec { + color: #f5871f; + } + + /* a variable name */ + .var { + color: #c82829; + } + + /* a function name */ + .fun { + color: #4271ae; + } +} +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; + } + + .kwd { + color: #006; + font-weight: bold; + } + + .com { + color: #600; + font-style: italic; + } + + .typ { + color: #404; + font-weight: bold; + } + + .lit { + color: #044; + } + + .pun, + .opn, + .clo { + color: #440; + } + + .tag { + color: #006; + font-weight: bold; + } + + .atn { + color: #404; + } + + .atv { + color: #060; + } +} +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ +} + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ +} diff --git a/docs/tax-Remittance.js.html b/docs/tax-Remittance.js.html new file mode 100644 index 0000000..0cbadba --- /dev/null +++ b/docs/tax-Remittance.js.html @@ -0,0 +1,252 @@ + + + + + + tax-Remittance.js - Documentation + + + + + + + + + + + + + + + + +
+

tax-Remittance.js

+ +
+
+
import axios from "axios";
+import {
+  generateOAuthToken,
+  encryptSecurityCredential,
+  throwErrorMessages,
+  logErrorDetails,
+  callbackTrigger,
+  validateUrl,
+  handleCallbacks,
+} from "../utils/helpers.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name taxRemittance
+ * @description This API enables businesses to remit tax to Kenya Revenue Authority (KRA). To use this API, prior integration is required with KRA for tax declaration, payment registration number (PRN) generation, and exchange of other tax-related information.
+ * @summary Enables one to remit tax to Kenya Revenue Authority (KRA)
+ * @see {@link https://developer.safaricom.co.ke/APIs/TaxRemittance open external link}
+ * @param {Object} options Options for the tax remittance API.
+ * @param {string} options.initiator The M-Pesa API operator username with the tax remittance API initiator role.
+ * @param {number} options.amount The transaction amount.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {number} options.partyA This is your own shortcode from which the money will be deducted.
+ * @param {number} options.partyB The account to which money will be credited.
+ * @param {number} options.accountReference The payment registration number (PRN) issued by KRA
+ * @param {string} options.QueueTimeOutURL URL to notify in case of a request timeout before processing.
+ * @param {string} options.resultURL URL to send transaction results after processing.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} remittanceResponse and (optional) conditionalCallbackData.
+ */
+async function taxRemittance({
+  initiator,
+  amount,
+  partyA,
+  partyB,
+  accountReference,
+  QueueTimeOutURL,
+  remarks,
+  resultURL,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleTaxRemittanceCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  try {
+    validateUrl(resultURL, "resultURL");
+    validateUrl(QueueTimeOutURL, "timeoutUrl");
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+
+    // Default configurations
+    const config = {
+      commandId: "PayTaxToKRA",
+      senderIdentifierType: "4",
+      receiverIdentifierType: "4",
+    };
+    const responseBody = await req.post("/mpesa/b2b/v1/remittax", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      SenderIdentifierType: config.senderIdentifierType,
+      RecieverIdentifierType: config.receiverIdentifierType,
+      Amount: amount,
+      PartyA: partyA,
+      PartyB: partyB,
+      AccountReference: accountReference,
+      Remarks: remarks,
+      QueueTimeOutURL: QueueTimeOutURL,
+      ResultURL: resultURL,
+    });
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+    return { remittanceResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for taxRemittance has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/b2b/v1/remittax",
+          method: "POST",
+          payload: {
+            initiator,
+            amount,
+            partyA,
+            partyB,
+            accountReference,
+            QueueTimeOutURL,
+            resultURL,
+            remarks
+          },
+        },
+        "Tax remittance error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleTaxRemittanceCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "taxRemittance");
+};
+
+export { taxRemittance, handleTaxRemittanceCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/docs/transaction-Status.js.html b/docs/transaction-Status.js.html new file mode 100644 index 0000000..ba1a03b --- /dev/null +++ b/docs/transaction-Status.js.html @@ -0,0 +1,257 @@ + + + + + + transaction-Status.js - Documentation + + + + + + + + + + + + + + + + +
+

transaction-Status.js

+ +
+
+
import axios from "axios";
+import {
+  callbackTrigger,
+  encryptSecurityCredential,
+  generateOAuthToken,
+  handleCallbacks,
+  logErrorDetails,
+  throwErrorMessages,
+} from "../utils/helpers.js";
+import { IdentifierTypes } from "../utils/constants.js";
+
+// Globals
+let callbackHandlerInitialized = false;
+let conditionalCallbackData = {};
+
+/**
+ * @name transactionStatus
+ * @description Enables one to Check the status of an M-pesa transaction, using a unique identifier.
+ * @summary Check the status of a transaction.
+ * @see {@link https://developer.safaricom.co.ke/APIs/TransactionStatus open external link}
+ * @param {Object} options Options for the transaction status API.
+ * @param {string} options.transactionId Unique identifier to identify a transaction on M-pesa
+ * @param {string} options.initiator The name of the initiator initiating the request.
+ * @param {number} options.partyA Organization/MSISDN receiving the transaction.
+ * @param {number} options.identifierType Type of organization receiving the transaction.
+ * @param {string} options.remarks Information to be associated with the transaction.
+ * @param {string} options.occasion Information to be associated with the transaction.
+ * @param {string} options.OriginatorConversationID This is a globally unique identifier for the transaction request returned by the API proxy upon successful submission.
+ * @param {string} options.QueueTimeOutURL URL for storing information about timeout transactions.
+ * @param {string} options.resultURL The path that stores information of a transaction.
+ * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging
+ * @returns {Promise<Object>} transactionStatusResponse and (optional) conditionalCallbackData.
+ */
+async function transactionStatus({
+  transactionId,
+  partyA,
+  identifierType,
+  QueueTimeOutURL,
+  OriginatorConversationID,
+  remarks,
+  occasion,
+  resultURL,
+  initiator,
+  proErrorLogging = false,
+}) {
+  if (!callbackHandlerInitialized) {
+    console.info(
+      "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleTransactStatusCallbacks') was not called. Ignore if handling manually.\x1b[0m",
+    );
+  }
+  /**
+   * @param {number} validIdentifierTypes - Expected identifiers include const IdentifierTypes = { MSISDN: 1, TILL_NUMBER: 2, ORG_SHORTCODE: 4 };
+   */
+  const validIdentifierTypes = Object.values(IdentifierTypes);
+  if (!validIdentifierTypes.includes(identifierType)) {
+    throw new Error(
+      `Invalid identifierType provided. Must be one of: ${validIdentifierTypes.join(", ")}`,
+    );
+  }
+  try {
+    const { accessToken, baseURL } = await generateOAuthToken();
+    const req = axios.create({
+      baseURL,
+      headers: {
+        Authorization: `Bearer ${accessToken}`,
+        "Content-Type": "application/json",
+      },
+    });
+    // Default configurations
+    const config = {
+      commandId: "TransactionStatusQuery",
+    };
+    const responseBody = await req.post("/mpesa/transactionstatus/v1/query", {
+      Initiator: initiator,
+      SecurityCredential: encryptSecurityCredential(),
+      CommandID: config.commandId,
+      TransactionID: transactionId,
+      PartyA: partyA,
+      OriginatorConversationID,
+      IdentifierType: identifierType,
+      ResultURL: resultURL,
+      QueueTimeOutURL: QueueTimeOutURL,
+      Remarks: remarks,
+      Occasion: occasion,
+    });
+    conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized);
+    return { transactStatusResponse: responseBody.data, conditionalCallbackData };
+  } catch (error) {
+    if (proErrorLogging) {
+      console.info(
+        "\x1b[35m%s\x1b[0m",
+        "Advanced error logging for transactionStatus has been initialized",
+      );
+      logErrorDetails(
+        error,
+        {
+          apiEndpoint: "/mpesa/transactionstatus/v1/query",
+          method: "POST",
+          payload: {
+            transactionId,
+            partyA,
+            identifierType,
+            QueueTimeOutURL,
+            resultURL,
+            initiator,
+            remarks,
+            occasion
+          },
+        },
+        "Transaction status error details:",
+      );
+    }
+    throw throwErrorMessages(error);
+  }
+}
+
+const handleTransactStatusCallbacks = async (app) => {
+  callbackHandlerInitialized = true;
+  await handleCallbacks(app, "transactionStatus");
+};
+
+export { transactionStatus, handleTransactStatusCallbacks };
+
+
+
+
+ +
+ +
+ Generated by JSDoc 4.0.4 on + Fri Feb 28 2025 10:29:32 GMT+0300 (East Africa Time) using the Minami + theme. +
+ + + + + diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..56a2d41 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,8 @@ +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default [ + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { languageOptions: { globals: globals.browser } }, + ...tseslint.configs.recommended, +]; diff --git a/image.jpg b/image.jpg new file mode 100644 index 0000000..44fb8c2 Binary files /dev/null and b/image.jpg differ diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..4f13dad --- /dev/null +++ b/index.d.ts @@ -0,0 +1,391 @@ +/** + * @name balanceQueryOptions + * @param {Object} options Options for the balance query API. + * @param {number} options.partyA The shortcode of the querying organization. + * @param {number} options.identifierType Type of the querying organization. + * @param {String} options.QueueTimeOutURL URL to receive timeout messages. + * @param {String} options.resultURL URL to receive the result message. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {String} options.initiator The credential/username for authentication. + */ +export interface balanceQueryOptions { + partyA: number; + identifierType: number; + QueueTimeOutURL: string; + resultURL: string; + initiator: string; + remarks: string; +} + +/** + * @name b2cRequestOptions + * @param {Object} options Options for the B2C payment request. + * @param {number} options.partyA The B2C organization shortcode sending the money. + * @param {string} options.partyB Customer mobile number (with country code, e.g., 254). + * @param {number} options.amount The amount being transacted. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {string} options.QueueTimeOutURL URL for timeout notifications. + * @param {string} options.resultURL URL for M-PESA to send payment processing notifications. + * @param {string} options.commandId Unique command specifying B2C transaction type (e.g., BusinessPayment). + * @param {string} options.initiatorName API user created by Business Administrator for B2C transactions. + */ +export interface b2cRequestOptions { + partyA: number; + partyB: string; + amount: number; + QueueTimeOutURL: string; + resultURL: string; + commandId: string; + initiatorName: string; + remarks: string; + occasion: string; +} + +/** + * @name c2bRegisterOptions + * @param {Object} options Options for the C2B Register URL. + * @param {string} options.confirmationURL URL to receive confirmation upon payment completion. + * @param {string} options.validationURL URL to receive validation upon payment submission (default: external validation disabled). + * @param {number} options.shortCode Unique M-PESA pay bill/till number. + * @param {string} options.responseType Action if validation URL is unreachable (values: Completed or Cancelled). + */ +export interface c2bRegisterOptions { + confirmationURL: string; + validationURL: string; + shortCode: number; + responseType: string; +} + +/** + * @name c2bSimulateOptions + * @param {Object} options Options for the C2B simulation. + * @param {string} options.msisdn The MSISDN receiving the transaction + * @param {number} options.amount Transaction amount. + * @param {string} options.billRefNumber Bill reference number e.g. "invoice008". + * @param {number} options.shortCode Usually, a unique number is tagged to an M-PESA pay bill/till number of the organization*/ +export interface c2bSimulateOptions { + msisdn: string; + amount: number; + billRefNumber: string; + shortCode: number; +} + +/** + * @name mpesaSimulateOptions + * @param {Object} options Options for M-Pesa express API. + * @param {string} options.partyA Sender's Safaricom mobile number (M-PESA registered). + * @param {string} options.phoneNumber Mobile number to receive the STK Pin Prompt (can be same as partyA). + * @param {number} options.amount Transaction amount. + * @param {string} options.transactionType "CustomerPayBillOnline" for PayBill and "CustomerBuyGoodsOnline" for Till Numbers. + * @param {string} options.callbackURL Secure URL for receiving notifications from M-Pesa API. + * @param {string} options.transactionDesc Information to be associated with the transaction. + * @param {string} options.accountRef Alphanumeric account reference (up to 12 characters) shown in the STK Pin Prompt. + * @param {number} options.partyB 5 to 6-digit number of the receiving organization. + */ +export interface mpesaSimulateOptions { + partyA: string; + phoneNumber: string; + amount: number; + callbackURL: string; + accountRef: string; + transactionType: string; + partyB: number; + transactionDesc: string; +} + +/** + * @name mpesaQueryOptions + * @param {Object} options Options for the Lipa Na M-Pesa query API. + * @param {string} options.checkoutRequestId Unique identifier for the processed checkout transaction. + * @param {number} options.businessShortCode Organization's shortcode (Paybill or Buygoods, 5-7 digits). + */ +export interface mpesaQueryOptions { + checkoutRequestId: string; + businessShortCode: number; +} + +/** + * @name reversalsOptions + * @param {Object} options Options for the reversal API. + * @param {string} options.transactionId Transaction ID for reversal (e.g., LKXXXX1234). + * @param {number} options.amount Amount to be reversed. + * @param {string} options.QueueTimeOutURL URL for timeout transaction details. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {string} options.resultURL URL for transaction details. + * @param {number} options.receiverParty Organization receiving the transaction. + * @param {string} options.initiator Name of the initiator of the request. + */ +export interface reversalsOptions { + transactionId: string; + amount: number; + QueueTimeOutURL: string; + resultURL: string; + receiverParty: string; + initiator: string; + receiverIdType: string; + remarks: string; + occasion: string; +} + +/** + * @name transactionStatusOptions + * @param {Object} options Options for the transaction status API. + * @param {string} options.transactionId Unique identifier for the transaction on M-Pesa. + * @param {string} options.initiator Name of the initiator of the request. + * @param {number} options.partyA Organization/MSISDN receiving the transaction. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {number} options.identifierType Type of organization receiving the transaction. + * @param {string} options.OriginatorConversationID This is a globally unique identifier for the transaction request returned by the API proxy upon successful submission. + * @param {string} options.QueueTimeOutURL URL for timeout transaction details. + * @param {string} options.resultURL URL for transaction details. + */ +export interface transactionStatusOptions { + transactionId: string; + partyA: number; + identifierType: number; + QueueTimeOutURL: string; + resultURL: string; + initiator: string; + OriginatorConversationID: string; + remarks: string; + occasion: string; +} + +/** + * @name generateQrCodeOptions + * @param {Object} options Options for the QR code generation request. + * @param {string} options.merchantName Name of the company or M-Pesa merchant requesting the QR code. + * @param {string} options.refNo Unique reference number for the transaction. + * @param {number} options.amount Total amount for the sale or transaction. + * @param {string} options.trxCode Transaction type (BG, WA, PB, SM, SB). + * @param {string} options.cpi Credit Party Identifier (e.g., mobile number, business number). + * @param {string} options.size QR code image size in pixels (square). + * */ +export interface generateQrCodeOptions { + merchantName: string; + refNo: string; + amount: number; + trxCode: "BG" | "WA" | "PB" | "SM" | "SB"; + cpi: string; + size: string; +} + +/** + * @name b2cTopUpOptions + * @param {Object} options B2C account top-up request options. + * @param {string} options.initiator M-Pesa API operator username with Org Business Pay to Bulk API role. + * @param {number} options.amount Transaction amount. + * @param {number} options.partyA Shortcode from which money will be deducted. + * @param {number} options.partyB Shortcode to which money will be moved. + * @param {string} options.remarks Information to be associated with the transaction. * @param {number} options.accountReference Transaction identifier. + * @param {number} [options.requester] Optional consumer’s mobile number (if paying on their behalf). + * @param {string} options.QueueTimeOutURL URL for timeout notifications. + * @param {string} options.resultURL URL for sending transaction results after processing. + */ +export interface b2cTopUpOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + requester?: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} + +/** + * @name businessPaybillOptions + * @param {Object} options Options for the business pay bill. + * @param {string} options.initiator M-Pesa API operator username with Org Business Pay Bill API role. + * @param {number} options.amount Transaction amount. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {number} options.partyA Shortcode from which money will be deducted. + * @param {number} options.partyB Shortcode to which money will be moved. + * @param {number} options.accountReference Account number for the payment (up to 13 characters). + * @param {number} [options.requester] Optional consumer’s mobile number (if paying on their behalf). + * @param {string} options.QueueTimeOutURL URL for timeout notifications. + * @param {string} options.resultURL URL for sending transaction results after processing. + */ +export interface businessPaybillOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + requester?: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} + +/** + * @name taxRemittanceOptions + * @param {Object} options Options for the tax remittance API. + * @param {string} options.initiator M-Pesa API operator username with tax remittance API role. + * @param {number} options.amount Transaction amount. + * @param {number} options.partyA Shortcode from which money will be deducted. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {number} options.partyB Account to which money will be credited. + * @param {number} options.accountReference Payment registration number (PRN) from KRA. + * @param {string} options.QueueTimeOutURL URL for timeout notifications before processing. + * @param {string} options.resultURL URL for sending transaction results after processing. + */ +export interface taxRemittanceOptions { + initiator: string; + amount: number; + partyA: number; + partyB: number; + accountReference: number; + QueueTimeOutURL: string; + resultURL: string; + remarks: string; +} + +declare const mpesa: { + /** + * @name balanceQuery + * @description The Account Balance API is used to request the account balance of a short code. This can be used for both B2C, buy goods and pay bill accounts. + * @summary Retrieves the balance of a short code associated with the developer account, supporting B2C, buy goods, and pay bill accounts. + * @see {@link https://developer.safaricom.co.ke/APIs/AccountBalance open external link} + */ + balanceQuery(options: balanceQueryOptions): Promise; + /** + * @name b2cRequest + * @description B2C API can be used in several scenarios by businesses that require to either make Salary Payments, Cashback payments, Promotional Payments(e.g. betting winning payouts), winnings, financial institutions withdrawal of funds, loan disbursements, etc. + * @summary B2C payments involve a business sending money to an individual. This is a direct transaction from a business shortcode to a consumer's mobile number (MSISDN). + * @see {@link https://developer.safaricom.co.ke/APIs/BusinessToCustomer open external link} + */ + b2cRequest(options: b2cRequestOptions): Promise; + /** + * @name c2BRegister + * @description Register URL API works hand in hand with Customer to Business (C2B) APIs and allows receiving payment notifications to your paybill. This API enables you to register the callback URLs via which you shall receive notifications for payments to your pay bill/till numbers + * @summary Registers callback validation and confirmation URLs on M-Pesa to receive payment notifications for your paybill/till numbers. + * @see {@link https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL open external link} + */ + c2BRegister(options: c2bRegisterOptions): Promise; + /** + * @name c2bSimulate + * @description This function simulates a C2B (Customer to Business) transaction by initiating a payment from a phone number to a business shortcode. + * @summary This API initiates a payment from a phone number to a business shortcode + * @see {@link https://developer.safaricom.co.ke/c2b/apis/post/simulate open external link} + */ + c2bSimulate(options: c2bSimulateOptions): Promise; + /** + * @name mpesaSimulate + * @description Lipa na M-PESA online API also known as M-PESA express (STK Push/NI push) is a Merchant/Business initiated C2B (Customer to Business) Payment. + * @summary Enable you to send a payment prompt on the customer's phone to your customer's M-PESA registered phone number + * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressSimulate open external link} + */ + mpesaSimulate(options: mpesaSimulateOptions): Promise; + /** + * @name mpesaQuery + * @description This API endpoint enables one to check the status of a Lipa Na M-Pesa Online Payment. + * @summary Fetches the transaction status of a Lipa na M-Pesa payment + * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressQuery open external link} + */ + mpesaQuery(options: mpesaQueryOptions): Promise; + /** + * @name reversals + * @description Enables one to reverse a previously successful Mpesa (simulate) transaction, using a unique identifier + * @summary Reverse successful Mpesa transaction + * @see {@link https://developer.safaricom.co.ke/APIs/Reversal open external link} + */ + reversals(options: reversalsOptions): Promise; + /** + * @name transactionStatus + * @description Enables one to Check the status of an Mpesa transaction, using a unique identifier + * @summary Fetches Mpesa transaction status + * @see {@link https://developer.safaricom.co.ke/APIs/TransactionStatus open external link} + */ + transactionStatus(options: transactionStatusOptions): Promise; + /** + * @name generateQrCode + * @description This generates a Dynamic QR which enables Safaricom M-PESA customers who have My Safaricom App or M-PESA app, to scan a QR (Quick Response) code, to capture till number and amount + * @summary Generates QR codes for customers using My Safaricom app + * @see {@link https://developer.safaricom.co.ke/APIs/DynamicQRCode open external link} + */ + generateQrCode(options: generateQrCodeOptions): Promise; + /** + *@name b2cTopUp + *@description B2C Account Top-Up - Use this API to load funds to a B2C shortcode directly for disbursement. + *@summary Moves money from your MMF/Working account to the recipient’s utility account. + * @see {@link https://developer.safaricom.co.ke/APIs/B2CAccountTopUp open external link} + */ + b2cTopUp(options: b2cTopUpOptions): Promise; + /** + * @name businessPayBill + * @description This API enables you to pay bills directly from your business account to a pay bill number, or a paybill store. You can use this API to pay on behalf of a consumer/requester. The transaction moves money from your MMF/Working account to the recipient’s utility account. + * @summary Facilitates bill payments from a business account to a paybill number, transferring funds to the recipient’s utility account. + * @see {@link https://developer.safaricom.co.ke/APIs/BusinessPayBill open external link} + */ + businessPayBill(options: businessPaybillOptions): Promise; + /** + * @name taxRemittance + * @description This API enables businesses to remit tax to Kenya Revenue Authority (KRA). To use this API, prior integration is required with KRA for tax declaration, payment registration number (PRN) generation, and exchange of other tax-related information. + * @summary Enables one to remit tax to Kenya Revenue Authority (KRA) + * @see {@link https://developer.safaricom.co.ke/APIs/TaxRemittance open external link} + */ + taxRemittance(options: taxRemittanceOptions): Promise; +}; + +interface AppWithUse { + /** + * Registers a middleware function. + * @param middleware The middleware function to register. + */ + use(middleware: (...args: any[]) => void): void; +} + +declare const callbacks: { + /** + * @name handleBalanceQueryCallbacks + * @description Default callback handler for the balanceQuery API + **/ + handleBalanceQueryCallbacks: (app: AppWithUse) => void; + /** + * @name handleBusinessPaybillCallbacks + * @description Default callback handler for the businessPaybill API + **/ + handleBusinessPaybillCallbacks: (app: AppWithUse) => void; + /** + * @name handleTaxRemittanceCallbacks + * @description Default callback handler for the taxRemittance API + **/ + handleTaxRemittanceCallbacks: (app: AppWithUse) => void; + /** + * @name handleB2cTopUpCallbacks + * @description Default callback handler for the b2cTopUp API + **/ + handleB2cTopUpCallbacks: (app: AppWithUse) => void; + /** + * @name handleTransactStatusCallbacks + * @description Default callback handler for the transaction status API + **/ + handleTransactStatusCallbacks: (app: AppWithUse) => void; + /** + * @name handleB2cRequestCallbacks + * @description Default callback handler for the b2cRequest API + **/ + handleB2cRequestCallbacks: (app: AppWithUse) => void; + /** + * @name handleC2bRegisterCallbacks + * @description Default callback handler for the c2bRegister API + **/ + handleC2bRegisterCallbacks: (app: AppWithUse) => void; + /** + * @name handleReversalCallbacks + * @description Default callback handler for the reversals API + **/ + handleReversalCallbacks: (app: AppWithUse) => void; + /** + * @name handleMpesaSimulateCallbacks + * @description Default callback handler for the mpesaSimulate API + **/ + handleMpesaSimulateCallbacks: (app: AppWithUse) => void; +}; + +export { mpesa, callbacks }; diff --git a/index.js b/index.js new file mode 100644 index 0000000..8f6aa09 --- /dev/null +++ b/index.js @@ -0,0 +1,68 @@ +import { + balanceQuery, + handleBalanceQueryCallbacks, +} from "./lib/core/apis/balance-Query.js"; +import { + b2cRequest, + handleB2cRequestCallbacks, +} from "./lib/core/apis/b2c-Request.js"; +import { + c2bRegister, + handleC2bRegisterCallbacks, +} from "./lib/core/apis/c2b-Register.js"; +import { + transactionStatus, + handleTransactStatusCallbacks, +} from "./lib/core/apis/transaction-Status.js"; +import { + b2cTopUp, + handleB2cTopUpCallbacks, +} from "./lib/core/apis/b2c-Topup.js"; +import { + businessPaybill, + handleBusinessPaybillCallbacks, +} from "./lib/core/apis/business-Paybill.js"; +import { + taxRemittance, + handleTaxRemittanceCallbacks, +} from "./lib/core/apis/tax-Remittance.js"; +import { + reversals, + handleReversalCallbacks, +} from "./lib/core/apis/reversals.js"; +import { + mpesaSimulate, + handleMpesaSimulateCallbacks, +} from "./lib/core/apis/mpesa-Simulate.js"; +import { c2bSimulate } from "./lib/core/apis/c2b-Simulate.js"; +import { mpesaQuery } from "./lib/core/apis/mpesa-Query.js"; +import { generateQrCode } from "./lib/core/apis/qr-Generate.js"; + +const mpesa = { + balanceQuery, + b2cRequest, + c2bRegister, + c2bSimulate, + mpesaSimulate, + mpesaQuery, + reversals, + generateQrCode, + transactionStatus, + b2cTopUp, + businessPaybill, + taxRemittance, +}; + +const callbacks = { + handleBalanceQueryCallbacks, + handleBusinessPaybillCallbacks, + handleTaxRemittanceCallbacks, + handleB2cTopUpCallbacks, + handleTransactStatusCallbacks, + handleB2cRequestCallbacks, + handleC2bRegisterCallbacks, + handleReversalCallbacks, + handleMpesaSimulateCallbacks, +}; + +export { mpesa, callbacks }; diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..9ddfd1e --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,25 @@ +{ + "source": { + "include": ["lib/core/apis", "lib/core/JSDOC.md"], + "includePattern": ".js$", + "excludePattern": "(node_modules/|docs)" + }, + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc"] + }, + "plugins": ["plugins/markdown"], + "opts": { + "destination": "./docs/", + "encoding": "utf8", + "private": true, + "recurse": true, + "template": "./node_modules/minami" + }, + "templates": { + "cleverLinks": false, + "monospaceLinks": true, + "useLongnameInNav": false, + "showInheritedInNav": true + } +} diff --git a/lib/core/JSDOC.md b/lib/core/JSDOC.md new file mode 100644 index 0000000..d7a03bd --- /dev/null +++ b/lib/core/JSDOC.md @@ -0,0 +1,25 @@ +# MPESA-NODE LIBRARY + +### JSDocs guide + +## About + +This documentation is generated using JSDoc and is designed to help developers accurately map fields to API endpoints. It provides a clear understanding of which fields are preconfigured by default and which can be modified based on your requirements. + +By referring to this guide, you can ensure that you're using the API correctly and efficiently. Whether you're integrating the library or extending its functionality, this documentation will serve as a valuable reference. + +## Keeping Documentation Up to Date + +If you're contributing to the project, make sure to regenerate the documentation whenever changes are made to the API. Use the following commands: + +### Generate Documentation + +After updating the library, you may **optionally run** the commands below to regenerate the documentation. However, if you prefer, you can leave this task to the repository maintainer. + +**npm**:`npm docs` + +**yarn**:`yarn docs` + +### Takeaways + +Keeping the documentation updated ensures that all contributors and users have access to accurate and up-to-date information. diff --git a/lib/core/apis/b2c-Request.js b/lib/core/apis/b2c-Request.js new file mode 100644 index 0000000..1592e1d --- /dev/null +++ b/lib/core/apis/b2c-Request.js @@ -0,0 +1,127 @@ +import axios from "axios"; +import { CommandIDs } from "../utils/constants.js"; +import { + callbackTrigger, + encryptSecurityCredential, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + originatorID, + throwErrorMessages, + validateFormatPhone, + validateUrl, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name b2cRequest + * @description B2C API can be used in several scenarios by businesses that require to either make Salary Payments, Cashback payments, Promotional Payments(e.g. betting winning payouts), winnings, financial institutions withdrawal of funds, loan disbursements, etc. + * @summary B2C payments involve a business sending money to an individual. This is a direct transaction from a business shortcode to a consumer's mobile number (MSISDN). + * @see {@link https://developer.safaricom.co.ke/APIs/BusinessToCustomer open external link} + * @param {Object} options Options for the B2C payment request. + * @param {number} options.partyA The B2C organization shortcode sending the money. + * @param {string} options.partyB Customer mobile number (with country code, e.g., 254). + * @param {number} options.amount The amount being transacted. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {string} options.QueueTimeOutURL URL for timeout notifications. + * @param {string} options.resultURL URL for M-PESA to send payment processing notifications. + * @param {string} options.commandId Unique command specifying B2C transaction type (e.g., BusinessPayment). + * @param {string} options.initiatorName API user created by Business Administrator for B2C transactions. + * @param {boolean} [options.proErrorLogging=false] Logs out advanced error details - good for debugging. + * @return {Promise} b2cRequestResponse and (optional) conditionalCallbackData. */ +async function b2cRequest({ + partyA, + partyB, + amount, + QueueTimeOutURL, + remarks, + occasion, + resultURL, + commandId, + initiatorName, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleB2cRequestCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + /** + * @param {string} validCommandIds - loops through object values with strings "SalaryPayment", "BusinessPayment" PromotionPayment" + */ + const validCommandIds = Object.values(CommandIDs); + if (!validCommandIds.includes(commandId)) { + throw new Error( + `Invalid commandId provided. Must be one of: ${validCommandIds.join(", ")}`, + ); + } + const _msisdn = validateFormatPhone(partyB); + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "QueueTimeOutURL"); + const OriginatorConversationID = originatorID(); + const { accessToken, baseURL } = await generateOAuthToken(); + + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + const responseBody = await req.post("/mpesa/b2c/v3/paymentrequest", { + OriginatorConversationID, + InitiatorName: initiatorName, + SecurityCredential: encryptSecurityCredential(), + CommandID: commandId, + Amount: amount, + PartyA: partyA, + PartyB: _msisdn, + Remarks: remarks, + QueueTimeOutURL: QueueTimeOutURL, + ResultURL: resultURL, + Occasion: occasion, + }); + + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + + return { b2cRequestResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for b2cRequest has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/b2c/v3/paymentrequest", + method: "POST", + payload: { + partyA, + _msisdn, + amount, + QueueTimeOutURL, + resultURL, + commandId, + initiatorName, + occasion, + remarks, + }, + }, + "B2C transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} +const handleB2cRequestCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "b2cRequest"); +}; +export { b2cRequest, handleB2cRequestCallbacks }; diff --git a/lib/core/apis/b2c-Topup.js b/lib/core/apis/b2c-Topup.js new file mode 100644 index 0000000..80f931c --- /dev/null +++ b/lib/core/apis/b2c-Topup.js @@ -0,0 +1,122 @@ +import axios from "axios"; +import { + generateOAuthToken, + encryptSecurityCredential, + throwErrorMessages, + logErrorDetails, + callbackTrigger, + handleCallbacks, + validateUrl, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + *@name b2cTopUp + *@description This API enables you to load funds to a B2C shortcode directly for disbursement. The transaction moves money from your MMF/Working account to the recipient’s utility account. + *@summary Transfers funds from your MMF/Working account to the recipient's utility account for disbursement to a B2C shortcode. + * @see {@link https://developer.safaricom.co.ke/APIs/B2CAccountTopUp open external link} + * @param {Object} options B2C account top-up request options. + * @param {string} options.initiator The M-Pesa API operator username, who needs Org Business Pay to Bulk API initiator role. + * @param {number} options.amount The transaction amount. + * @param {number} options.partyA Your shortcode. The shortcode from which money will be deducted. + * @param {number} options.partyB The shortcode to which money will be moved + * @param {string} options.remarks Information to be associated with the transaction. + * @param {number} options.accountReference Identifier for the transaction. + * @param {number} [options.requester] Optional. The consumer’s mobile number on behalf of whom you are paying. + * @param {string} options.QueueTimeOutURL A URL that will be used to notify your system in case the request times out. + * @param {string} options.resultURL A URL that will be used to send transaction results after processing. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @return {Promise} b2cTopUpResponse and (optional) conditionalCallbackData. */ +async function b2cTopUp({ + initiator, + amount, + partyA, + partyB, + accountReference, + requester, + QueueTimeOutURL, + resultURL, + remarks, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleB2cTopUpCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "QueueTimeOutUrl"); + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + // Default configurations + const config = { + commandId: "BusinessPayToBulk", + senderIdentifierType: "4", + receiverIdentifierType: "4", + }; + + const responseBody = await req.post("mpesa/b2b/v1/paymentrequest", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + SenderIdentifierType: config.senderIdentifierType, + RecieverIdentifierType: config.receiverIdentifierType, + Amount: amount, + PartyA: partyA, + PartyB: partyB, + AccountReference: accountReference, + Requester: requester, + Remarks: remarks, + QueueTimeOutURL: QueueTimeOutURL, + ResultURL: resultURL, + }); + + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + + return { b2cTopUpResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for b2cTopUp has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/b2b/v1/paymentrequest", + method: "POST", + payload: { + initiator, + amount, + partyA, + partyB, + accountReference, + requester, + QueueTimeOutURL, + resultURL, + remarks, + }, + }, + "B2C account top-up error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleB2cTopUpCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "b2cTopUp"); +}; +export { b2cTopUp, handleB2cTopUpCallbacks }; diff --git a/lib/core/apis/balance-Query.js b/lib/core/apis/balance-Query.js new file mode 100644 index 0000000..48df31b --- /dev/null +++ b/lib/core/apis/balance-Query.js @@ -0,0 +1,120 @@ +import axios from "axios"; +import { + callbackTrigger, + encryptSecurityCredential, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, + validateUrl, +} from "../utils/helpers.js"; +import { IdentifierTypes } from "../utils/constants.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name balanceQuery + * @description The Account Balance API is used to request the account balance of a short code. This can be used for both B2C, buy goods and pay bill accounts. + * @summary Retrieves the balance of a short code associated with the developer account, supporting B2C, buy goods, and pay bill accounts. + * @see {@link https://developer.safaricom.co.ke/APIs/AccountBalance open external link} + * @param {Object} options Options for the balance query API. + * @param {number} options.partyA The shortcode of the querying organization. + * @param {number} options.identifierType Type of the querying organization. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {String} options.QueueTimeOutURL URL to receive timeout messages. + * @param {String} options.resultURL URL to receive the result message. + * @param {String} options.initiator The credential/username for authentication. + * @param {boolean} [options.proErrorLogging=false] Logs out advanced error details - good for debugging + * @return {Promise} balanceQueryResponse and (optional) conditionalCallbackData. + */ +async function balanceQuery({ + partyA, + identifierType, + QueueTimeOutURL, + resultURL, + initiator, + remarks, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleBalanceQueryCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + /** + * @param {number} validIdentifierTypes - Expected identifiers include const IdentifierTypes = { MSISDN: 1, TILL_NUMBER: 2, ORG_SHORTCODE: 4 }; + */ + const validIdentifierTypes = Object.values(IdentifierTypes); + if (!validIdentifierTypes.includes(identifierType)) { + throw new Error( + `Invalid identifierType provided. Must be one of: ${validIdentifierTypes.join(", ")}`, + ); + } + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "timeoutUrl"); + const { accessToken, baseURL } = await generateOAuthToken(); + + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + // Default configurations + const config = { + commandId: "AccountBalance", + remarks: "OK", + }; + + const responseBody = await req.post("/mpesa/accountbalance/v1/query", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + PartyA: partyA, + IdentifierType: identifierType, + Remarks: remarks, + QueueTimeOutURL: QueueTimeOutURL, + ResultURL: resultURL, + }); + + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + + return { balanceQueryResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for balanceQuery has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/accountbalance/v1/query", + method: "POST", + payload: { + partyA, + identifierType, + QueueTimeOutURL, + resultURL, + initiator, + remarks, + }, + }, + "Balance query error details:", + ); + } + throw await throwErrorMessages(error); + } +} + +const handleBalanceQueryCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "balanceQuery"); +}; + +export { balanceQuery, handleBalanceQueryCallbacks }; diff --git a/lib/core/apis/business-Paybill.js b/lib/core/apis/business-Paybill.js new file mode 100644 index 0000000..2ad097a --- /dev/null +++ b/lib/core/apis/business-Paybill.js @@ -0,0 +1,125 @@ +import axios from "axios"; +import { + callbackTrigger, + encryptSecurityCredential, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, + validateUrl, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name businessPaybill + * @description This API enables you to pay bills directly from your business account to a pay bill number, or a paybill store. You can use this API to pay on behalf of a consumer/requester. The transaction moves money from your MMF/Working account to the recipient’s utility account. + * @summary Facilitates bill payments from a business account to a paybill number, transferring funds to the recipient’s utility account. + * @see {@link https://developer.safaricom.co.ke/APIs/BusinessPayBill open external link} + * @param {Object} options Options for the business pay bill. + * @param {string} options.initiator M-Pesa API operator username with Org Business Pay Bill API role. + * @param {number} options.amount Transaction amount. + * @param {number} options.partyA Shortcode from which money will be deducted. + * @param {number} options.partyB Shortcode to which money will be moved. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {number} options.accountReference Account number for the payment (up to 13 characters). + * @param {number} [options.requester] Optional consumer’s mobile number (if paying on their behalf). + * @param {string} options.QueueTimeOutURL URL for timeout notifications. + * @param {string} options.resultURL URL for sending transaction results after processing. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @return {Promise} businessPaybillResponse and (optional) conditionalCallbackData. + */ +async function businessPaybill({ + initiator, + amount, + partyA, + partyB, + remarks, + accountReference, + requester, + QueueTimeOutURL, + resultURL, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleBusinessPaybillCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "timeoutUrl"); + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + // Default configurations + const config = { + commandId: "BusinessPayBill", + senderIdentifierType: "4", + receiverIdentifierType: "4", + }; + const responseBody = await req.post("/mpesa/b2b/v1/paymentrequest", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + SenderIdentifierType: config.senderIdentifierType, + RecieverIdentifierType: config.receiverIdentifierType, + Amount: amount, + PartyA: partyA, + PartyB: partyB, + AccountReference: accountReference, + Requester: requester, + Remarks: remarks, + QueueTimeOutURL: QueueTimeOutURL, + ResultURL: resultURL, + }); + + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + + return { + businessPaybillResponse: responseBody.data, + conditionalCallbackData, + }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for businessPaybill has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/b2b/v1/paymentrequest", + method: "POST", + payload: { + initiator, + amount, + partyA, + partyB, + accountReference, + requester, + QueueTimeOutURL, + resultURL, + remarks, + }, + }, + "Business Pay Bill transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleBusinessPaybillCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "businessPaybill"); +}; + +export { businessPaybill, handleBusinessPaybillCallbacks }; diff --git a/lib/core/apis/c2b-Register.js b/lib/core/apis/c2b-Register.js new file mode 100644 index 0000000..0334b2f --- /dev/null +++ b/lib/core/apis/c2b-Register.js @@ -0,0 +1,99 @@ +import axios from "axios"; +import { + callbackTrigger, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, + validateUrl, +} from "../utils/helpers.js"; +import { responseTypes } from "../utils/constants.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name C2BRegister + * @description Register URL API works hand in hand with Customer to Business (C2B) APIs and allows receiving payment notifications to your paybill. This API enables you to register the callback URLs via which you shall receive notifications for payments to your pay bill/till numbers + * @summary Registers callback validation and confirmation URLs on M-Pesa to receive payment notifications for your paybill/till numbers. + * @see {@link https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL open external link} + * @param {Object} options Options for the C2B Register URL. + * @param {string} options.confirmationURL URL to receive confirmation upon payment completion. + * @param {string} options.validationURL URL to receive validation upon payment submission (default: external validation disabled). + * @param {number} options.shortCode Unique M-PESA pay bill/till number. + * @param {string} options.responseType Action if validation URL is unreachable (values: Completed or Cancelled). + * @param {boolean} [options.proErrorLogging] Logs out detailed errors for debugging purposes + * @return {Promise} c2bRegisterResponse and (optional) conditionalCallbackData. + */ +async function c2bRegister({ + confirmationURL, + validationURL, + shortCode, + responseType, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleC2bRegisterCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + /** + * @param {string} validResponseTypes - Should either be Completed or Cancelled + */ + const validResponseTypes = Object.values(responseTypes); + if (!validResponseTypes.includes(responseType)) { + throw new Error( + `Invalid responseType provided. Must be one of: ${validResponseTypes.join(", ")}`, + ); + } + try { + validateUrl(confirmationURL, "confirmationURL"); + validateUrl(validationURL, "validationURL"); + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + const responseBody = await req.post("/mpesa/c2b/v1/registerurl", { + ShortCode: shortCode, + ResponseType: responseType, + ConfirmationURL: confirmationURL, + ValidationURL: validationURL, + }); + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + return { c2bRegisterResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for c2bRegister has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/c2b/v1/registerurl", + method: "POST", + payload: { + confirmationURL, + validationURL, + shortCode, + responseType, + }, + }, + "C2B Register transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleC2bRegisterCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "c2bRegister"); +}; + +export { c2bRegister, handleC2bRegisterCallbacks }; diff --git a/lib/core/apis/c2b-Simulate.js b/lib/core/apis/c2b-Simulate.js new file mode 100644 index 0000000..1786b3f --- /dev/null +++ b/lib/core/apis/c2b-Simulate.js @@ -0,0 +1,79 @@ +import { + generateOAuthToken, + logErrorDetails, + throwErrorMessages, + validateFormatPhone, +} from "../utils/helpers.js"; +import axios from "axios"; + +/** + * @name c2bSimulate + * @description This function simulates a C2B (Customer to Business) transaction by initiating a payment from an MSISDN to a business shortcode. + * @summary Simulate a transaction from an MSISDN to a business shortcode + * @see {@link https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL open external link} + * @param {Object} options Options for the C2B simulation. + * @param {string} options.msisdn The MSISDN receiving the transaction + * @param {number} options.amount Transaction amount. + * @param {string} options.billRefNumber Bill reference number e.g. "invoice008". + * @param {number} options.shortCode Usually, a unique number is tagged to an M-PESA pay bill/till number of the organization + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @return {Promise} c2bSimulateResponse. + */ +async function c2bSimulate({ + msisdn, + amount, + billRefNumber, + shortCode, + proErrorLogging = false, +}) { + /** SIMULATE SHOULD ONLY BE PERFORMED IN SANDBOX MODE, NEVER IN PRODUCTION **/ + const { accessToken, baseURL } = await generateOAuthToken(); + if (baseURL === "https://api.safaricom.co.ke") { + throw new Error( + "Simulation is allowed only in development or sandbox environment!", + ); + } + try { + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + const config = { + commandId: "CustomerPayBillOnline", + }; + const responseBody = await req.post(`/mpesa/c2b/v1/simulate`, { + ShortCode: shortCode, + CommandID: config.commandId, + Amount: amount, + Msisdn: validateFormatPhone(msisdn), + BillRefNumber: billRefNumber, + }); + return { c2bSimulateResponse: responseBody.data }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for c2bSimulate has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/c2b/v1/simulate", + method: "POST", + payload: { + msisdn, + amount, + billRefNumber, + shortCode, + }, + }, + "C2B Simulation transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} +export { c2bSimulate }; diff --git a/lib/core/apis/mpesa-Query.js b/lib/core/apis/mpesa-Query.js new file mode 100644 index 0000000..3179a74 --- /dev/null +++ b/lib/core/apis/mpesa-Query.js @@ -0,0 +1,66 @@ +import { + generateMpesaCredentials, + generateOAuthToken, + logErrorDetails, + throwErrorMessages, +} from "../utils/helpers.js"; +import axios from "axios"; + +/** + * @name mpesaQuery + * @description Use this API to check the status of a Lipa Na M-Pesa Online Payment. + * @summary Check transaction status of a Lipa na M-Pesa payment. + * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressQuery open external link} + * @param {Object} options Options for the Lipa Na M-Pesa query API. + * @param {string} options.checkoutRequestId Unique identifier for the processed checkout transaction. + * @param {number} options.businessShortCode Organization's shortcode (Paybill or Buygoods, 5-7 digits). + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} mpesaQueryResponse. + */ +async function mpesaQuery({ + checkoutRequestId, + businessShortCode, + proErrorLogging = false, +}) { + const { accessToken, baseURL } = await generateOAuthToken(); + const { password, timeStamp } = generateMpesaCredentials(businessShortCode); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + try { + const responseBody = await req.post("/mpesa/stkpushquery/v1/query", { + BusinessShortCode: businessShortCode, + Password: password, + Timestamp: timeStamp, + CheckoutRequestID: checkoutRequestId, + }); + + return { mpesaQueryResponse: responseBody.data }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for mpesaQuery has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/stkpushquery/v1/query", + method: "POST", + payload: { + businessShortCode, + checkoutRequestId, + }, + }, + "Mpesa Query transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} + +export { mpesaQuery }; diff --git a/lib/core/apis/mpesa-Simulate.js b/lib/core/apis/mpesa-Simulate.js new file mode 100644 index 0000000..a22d72b --- /dev/null +++ b/lib/core/apis/mpesa-Simulate.js @@ -0,0 +1,114 @@ +import axios from "axios"; +import { + callbackTrigger, + generateMpesaCredentials, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, + validateFormatPhone, + validateUrl, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name mpesaSimulate + * @description Lipa na M-PESA online API also known as M-PESA express (STK Push/NI push) is a Merchant/Business initiated C2B (Customer to Business) Payment. it enables you to send a payment prompt on the customer's phone (Popularly known as STK Push Prompt) to your customer's M-PESA registered phone number requesting them to enter their M-PESA pin to authorize and complete payment. + * @summary Sends a payment prompt to the customer's M-PESA registered phone number, requesting them to enter their M-PESA pin to authorize and complete payment. + * @see {@link https://developer.safaricom.co.ke/APIs/MpesaExpressSimulate open external link} + * @param {Object} options Options for M-Pesa express API. + * @param {string} options.partyA Sender's Safaricom mobile number (M-PESA registered). + * @param {string} options.phoneNumber Mobile number to receive the STK Pin Prompt (can be same as partyA). + * @param {number} options.amount Transaction amount. + * @param {string} options.transactionType "CustomerPayBillOnline" for PayBill and "CustomerBuyGoodsOnline" for Till Numbers. + * @param {string} options.callbackURL Secure URL for receiving notifications from M-Pesa API. + * @param {string} options.transactionDesc Information to be associated with the transaction. + * @param {string} options.accountRef Alphanumeric account reference (up to 12 characters) shown in the STK Pin Prompt (Org name). + * @param {number} options.partyB 5 to 6-digit number of the receiving organization. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} mpesaSimulateResponse and (optional) conditionalCallbackData. + */ +async function mpesaSimulate({ + partyA, + phoneNumber, + amount, + callbackURL, + accountRef, + partyB, + transactionType, + transactionDesc, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleMpesaSimulateCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + try { + validateUrl(callbackURL, "callbackURL"); + const { accessToken, baseURL } = await generateOAuthToken(); + const { password, timeStamp } = generateMpesaCredentials(partyB); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + const responseBody = await req.post("/mpesa/stkpush/v1/processrequest", { + BusinessShortCode: partyB, + Password: password, + Timestamp: timeStamp, + Amount: amount, + PartyA: validateFormatPhone(partyA), + PartyB: partyB, + PhoneNumber: validateFormatPhone(phoneNumber), + CallBackURL: callbackURL, + AccountReference: accountRef, + TransactionDesc: transactionDesc, + TransactionType: transactionType, + }); + conditionalCallbackData = await callbackTrigger( + callbackHandlerInitialized, + true, + ); + return { + mpesaSimulateResponse: responseBody.data, + conditionalCallbackData, + }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for mpesaSimulate has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/stkpush/v1/processrequest", + method: "POST", + payload: { + partyA, + phoneNumber, + amount, + callbackURL, + accountRef, + partyB, + transactionDesc, + }, + }, + "Mpesa Simulate transaction error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleMpesaSimulateCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "mpesaSimulate"); +}; +export { mpesaSimulate, handleMpesaSimulateCallbacks }; diff --git a/lib/core/apis/qr-Generate.js b/lib/core/apis/qr-Generate.js new file mode 100644 index 0000000..6929f12 --- /dev/null +++ b/lib/core/apis/qr-Generate.js @@ -0,0 +1,87 @@ +import axios from "axios"; +import { + generateOAuthToken, + logErrorDetails, + throwErrorMessages, +} from "../utils/helpers.js"; +import { trxCodeTypes } from "../utils/constants.js"; + +/** + * @name generateQrCode + * @description This generates a Dynamic QR which enables Safaricom M-PESA customers who have My Safaricom App or M-PESA app, to scan a QR (Quick Response) code, to capture till number and amount + * @summary Generates QR codes for customers using My Safaricom app + * @see {@link https://developer.safaricom.co.ke/APIs/DynamicQRCode open external link} + * @param {Object} options Options for the QR code generation request. + * @param {string} options.merchantName - The name of the company or M-Pesa merchant requesting the QR code. + * @param {string} options.refNo A unique reference number for the transaction. + * @param {number} options.amount The total amount for the sale or transaction. + * @param {string} options.trxCode Transaction type. Supported types: BG, WA, PB, SM, SB. + * @param {string} options.cpi Credit Party Identifier (e.g., mobile number, business number). + * @param {string} options.size Size of the QR code image in pixels. QR code image will always be square. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} generateQrcodeResponse. + */ +async function generateQrCode({ + merchantName, + refNo, + amount, + trxCode, + cpi, + size, + proErrorLogging = false, +}) { + /** + * @param {string} validTrxCodes - Only support: buy goods: "BG" - withdraw agent till: "WA" - paybill business number: "PB" - send money msisdn: "SM" and end to business msisdn: "SB" + */ + const validTrxCodes = Object.values(trxCodeTypes); + if (!validTrxCodes.includes(trxCode)) { + throw new Error( + `Invalid trxCode provided. Must be one of: ${validTrxCodes.join(", ")}`, + ); + } + try { + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + const responseBody = await req.post("/mpesa/qrcode/v1/generate", { + MerchantName: merchantName, + RefNo: refNo, + Amount: amount, + TrxCode: trxCode, + CPI: cpi, + Size: size, + }); + return { generateQrcodeResponse: responseBody.data }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for generateQrcode has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/qrcode/v1/generate", + method: "POST", + payload: { + merchantName, + refNo, + amount, + trxCode, + cpi, + size, + }, + }, + "QR code generation error details:", + ); + } + throw throwErrorMessages(error); + } +} + +export { generateQrCode }; diff --git a/lib/core/apis/reversals.js b/lib/core/apis/reversals.js new file mode 100644 index 0000000..17591f7 --- /dev/null +++ b/lib/core/apis/reversals.js @@ -0,0 +1,115 @@ +import axios from "axios"; +import { + callbackTrigger, + encryptSecurityCredential, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, + validateUrl, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name reversals + * @description Reverses a C2B M-Pesa transaction. Once a customer pays and there is a need to reverse the transaction, the organization will use this API to reverse the amount. + * @summary Reverses an M-pesa transaction + * @see {@link https://developer.safaricom.co.ke/APIs/Reversal open external link} + * @param {Object} options Options for the reversal API. + * @param {string} options.transactionId Transaction ID for reversal (e.g., LKXXXX1234). + * @param {number} options.amount Amount to be reversed. + * @param {string} options.QueueTimeOutURL URL for timeout transaction details. + * @param {string} options.resultURL URL for transaction details. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {number} options.receiverParty Organization receiving the transaction. + * @param {string} options.initiator Name of the initiator of the request. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} reversalsResponse and (optional) conditionalCallbackData. + */ +async function reversals({ + transactionId, + amount, + QueueTimeOutURL, + resultURL, + receiverParty, + initiator, + remarks, + occasion, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default callback handler ('handleReversalCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "timeoutUrl"); + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + // default configurations + const config = { + receiverIdType: "11", + commandId: "TransactionReversal", + }; + const responseBody = await req.post("/mpesa/reversal/v1/request", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + TransactionID: transactionId, + Amount: amount, + ReceiverParty: receiverParty, + RecieverIdentifierType: config.receiverIdType, + ResultURL: resultURL, + QueueTimeOutURL: QueueTimeOutURL, + Remarks: remarks, + Occasion: occasion, + }); + + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + + return { reversalsResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for reversals has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/reversal/v1/request", + method: "POST", + payload: { + transactionId, + amount, + QueueTimeOutURL, + resultURL, + receiverParty, + initiator, + remarks, + occasion, + }, + }, + "Transaction reversal error details:", + ); + } + throw throwErrorMessages(error); + } +} +const handleReversalCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "reversals"); +}; + +export { reversals, handleReversalCallbacks }; diff --git a/lib/core/apis/tax-Remittance.js b/lib/core/apis/tax-Remittance.js new file mode 100644 index 0000000..7981309 --- /dev/null +++ b/lib/core/apis/tax-Remittance.js @@ -0,0 +1,117 @@ +import axios from "axios"; +import { + generateOAuthToken, + encryptSecurityCredential, + throwErrorMessages, + logErrorDetails, + callbackTrigger, + validateUrl, + handleCallbacks, +} from "../utils/helpers.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name taxRemittance + * @description This API enables businesses to remit tax to Kenya Revenue Authority (KRA). To use this API, prior integration is required with KRA for tax declaration, payment registration number (PRN) generation, and exchange of other tax-related information. + * @summary Enables one to remit tax to Kenya Revenue Authority (KRA) + * @see {@link https://developer.safaricom.co.ke/APIs/TaxRemittance open external link} + * @param {Object} options Options for the tax remittance API. + * @param {string} options.initiator The M-Pesa API operator username with the tax remittance API initiator role. + * @param {number} options.amount The transaction amount. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {number} options.partyA This is your own shortcode from which the money will be deducted. + * @param {number} options.partyB The account to which money will be credited. + * @param {number} options.accountReference The payment registration number (PRN) issued by KRA + * @param {string} options.QueueTimeOutURL URL to notify in case of a request timeout before processing. + * @param {string} options.resultURL URL to send transaction results after processing. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} remittanceResponse and (optional) conditionalCallbackData. + */ +async function taxRemittance({ + initiator, + amount, + partyA, + partyB, + accountReference, + QueueTimeOutURL, + remarks, + resultURL, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleTaxRemittanceCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + try { + validateUrl(resultURL, "resultURL"); + validateUrl(QueueTimeOutURL, "timeoutUrl"); + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + // Default configurations + const config = { + commandId: "PayTaxToKRA", + senderIdentifierType: "4", + receiverIdentifierType: "4", + }; + const responseBody = await req.post("/mpesa/b2b/v1/remittax", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + SenderIdentifierType: config.senderIdentifierType, + RecieverIdentifierType: config.receiverIdentifierType, + Amount: amount, + PartyA: partyA, + PartyB: partyB, + AccountReference: accountReference, + Remarks: remarks, + QueueTimeOutURL: QueueTimeOutURL, + ResultURL: resultURL, + }); + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + return { remittanceResponse: responseBody.data, conditionalCallbackData }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for taxRemittance has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/b2b/v1/remittax", + method: "POST", + payload: { + initiator, + amount, + partyA, + partyB, + accountReference, + QueueTimeOutURL, + resultURL, + remarks, + }, + }, + "Tax remittance error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleTaxRemittanceCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "taxRemittance"); +}; + +export { taxRemittance, handleTaxRemittanceCallbacks }; diff --git a/lib/core/apis/transaction-Status.js b/lib/core/apis/transaction-Status.js new file mode 100644 index 0000000..a412efa --- /dev/null +++ b/lib/core/apis/transaction-Status.js @@ -0,0 +1,125 @@ +import axios from "axios"; +import { + callbackTrigger, + encryptSecurityCredential, + generateOAuthToken, + handleCallbacks, + logErrorDetails, + throwErrorMessages, +} from "../utils/helpers.js"; +import { IdentifierTypes } from "../utils/constants.js"; + +// Globals +let callbackHandlerInitialized = false; +let conditionalCallbackData = {}; + +/** + * @name transactionStatus + * @description Enables one to Check the status of an M-pesa transaction, using a unique identifier. + * @summary Check the status of a transaction. + * @see {@link https://developer.safaricom.co.ke/APIs/TransactionStatus open external link} + * @param {Object} options Options for the transaction status API. + * @param {string} options.transactionId Unique identifier to identify a transaction on M-pesa + * @param {string} options.initiator The name of the initiator initiating the request. + * @param {number} options.partyA Organization/MSISDN receiving the transaction. + * @param {number} options.identifierType Type of organization receiving the transaction. + * @param {string} options.remarks Information to be associated with the transaction. + * @param {string} options.occasion Information to be associated with the transaction. + * @param {string} options.OriginatorConversationID This is a globally unique identifier for the transaction request returned by the API proxy upon successful submission. + * @param {string} options.QueueTimeOutURL URL for storing information about timeout transactions. + * @param {string} options.resultURL The path that stores information of a transaction. + * @param {boolean} [options.proErrorLogging] Logs out advanced error details - good for debugging + * @returns {Promise} transactionStatusResponse and (optional) conditionalCallbackData. + */ +async function transactionStatus({ + transactionId, + partyA, + identifierType, + QueueTimeOutURL, + OriginatorConversationID, + remarks, + occasion, + resultURL, + initiator, + proErrorLogging = false, +}) { + if (!callbackHandlerInitialized) { + console.info( + "\x1b[42m\x1b[30m\x1b[1m The default balance query callback handler ('handleTransactStatusCallbacks') was not called. Ignore if handling manually.\x1b[0m", + ); + } + /** + * @param {number} validIdentifierTypes - Expected identifiers include const IdentifierTypes = { MSISDN: 1, TILL_NUMBER: 2, ORG_SHORTCODE: 4 }; + */ + const validIdentifierTypes = Object.values(IdentifierTypes); + if (!validIdentifierTypes.includes(identifierType)) { + throw new Error( + `Invalid identifierType provided. Must be one of: ${validIdentifierTypes.join(", ")}`, + ); + } + try { + const { accessToken, baseURL } = await generateOAuthToken(); + const req = axios.create({ + baseURL, + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + // Default configurations + const config = { + commandId: "TransactionStatusQuery", + }; + const responseBody = await req.post("/mpesa/transactionstatus/v1/query", { + Initiator: initiator, + SecurityCredential: encryptSecurityCredential(), + CommandID: config.commandId, + TransactionID: transactionId, + PartyA: partyA, + OriginatorConversationID, + IdentifierType: identifierType, + ResultURL: resultURL, + QueueTimeOutURL: QueueTimeOutURL, + Remarks: remarks, + Occasion: occasion, + }); + conditionalCallbackData = await callbackTrigger(callbackHandlerInitialized); + return { + transactStatusResponse: responseBody.data, + conditionalCallbackData, + }; + } catch (error) { + if (proErrorLogging) { + console.info( + "\x1b[35m%s\x1b[0m", + "Advanced error logging for transactionStatus has been initialized", + ); + logErrorDetails( + error, + { + apiEndpoint: "/mpesa/transactionstatus/v1/query", + method: "POST", + payload: { + transactionId, + partyA, + identifierType, + QueueTimeOutURL, + resultURL, + initiator, + remarks, + occasion, + }, + }, + "Transaction status error details:", + ); + } + throw throwErrorMessages(error); + } +} + +const handleTransactStatusCallbacks = async (app) => { + callbackHandlerInitialized = true; + await handleCallbacks(app, "transactionStatus"); +}; + +export { transactionStatus, handleTransactStatusCallbacks }; diff --git a/lib/core/utils/configs.js b/lib/core/utils/configs.js new file mode 100644 index 0000000..41b42a9 --- /dev/null +++ b/lib/core/utils/configs.js @@ -0,0 +1,85 @@ +import dotenv from "dotenv"; +import path from "path"; +import fs from "fs"; + +// Function to load environment variables from a specified path using dotenv +const loadEnv = (envPath) => dotenv.config({ path: envPath }); + +const fallbackAlt = fs.existsSync("./lib/tests/.env.local") + ? "./lib/tests/.env.local" + : "./lib/tests/.env"; +const primaryEnvPath = path.resolve(process.cwd(), ".env"); +const fallbackEnvPath = path.resolve(process.cwd(), fallbackAlt); + +// Function to check for the existence of .env files and load the appropriate one +const configSwapper = () => { + if (fs.existsSync(primaryEnvPath)) { + loadEnv(primaryEnvPath); + } else if (fs.existsSync(fallbackEnvPath)) { + loadEnv(fallbackEnvPath); + } else { + console.error("No .env file found. Please check your configuration."); + } +}; + +configSwapper(); +const { + MPESA_CONSUMER_KEY, // Consumer key for M-Pesa API authentication + MPESA_CONSUMER_SECRET, // Consumer secret for M-Pesa API authentication + MPESA_SECURITY_CREDENTIAL, // Encrypted security credential required for API requests + MPESA_PASS_KEY, // Pass key for specific M-Pesa transactions + MPESA_CERT_PATH_DEV, // Path to the development/sandbox certificate file used for encryption + MPESA_CERT_PATH_PROD, //Path to the production certificate file used for encryption + ENVIRONMENT, // Environment variable indicating sandbox or production mode +} = process.env; + +// Function to determine the base URL for API requests based on the environment (sandbox or production) +const baseURLSwapper = () => + ENVIRONMENT === "development" || ENVIRONMENT === "sandbox" + ? "https://sandbox.safaricom.co.ke" // Sandbox URL for testing + : "https://api.safaricom.co.ke"; // Production URL for live requests +const envCERTSwapper = () => + ENVIRONMENT === "development" || ENVIRONMENT === "sandbox" + ? MPESA_CERT_PATH_DEV + : MPESA_CERT_PATH_PROD; +const baseUrl = baseURLSwapper(); // Set baseUrl based on environment +const certificatePath = envCERTSwapper(); // Set encryption cert based on environment + +// Define configuration object with all necessary variables for easy access throughout the application +const globalConfigs = { + consumerKey: MPESA_CONSUMER_KEY, + consumerSecret: MPESA_CONSUMER_SECRET, + securityCredential: MPESA_SECURITY_CREDENTIAL, + passKey: MPESA_PASS_KEY, + certPath: certificatePath, + environment: ENVIRONMENT, + baseUrl, // Base URL set dynamically based on environment +}; + +// Validate required environment variables +const validateGlobalConfigs = () => { + const requiredConfigs = [ + "consumerKey", + "consumerSecret", + "securityCredential", + "passKey", + "certPath", + "environment", + "baseUrl", + ]; + + const missingConfigs = requiredConfigs.filter( + (config) => !globalConfigs[config], + ); + + if (missingConfigs.length > 0) { + throw new Error( + `Missing required environment variables: ${missingConfigs.join(", ")}`, + ); + } +}; + +// Call validation function to ensure all necessary environment variables are defined +validateGlobalConfigs(); + +export default globalConfigs; diff --git a/lib/core/utils/constants.js b/lib/core/utils/constants.js new file mode 100644 index 0000000..40ba3f4 --- /dev/null +++ b/lib/core/utils/constants.js @@ -0,0 +1,26 @@ +// Define constants for command IDs +const CommandIDs = { + SALARY_PAYMENT: "SalaryPayment", + BUSINESS_PAYMENT: "BusinessPayment", + PROMOTION_PAYMENT: "PromotionPayment", +}; +const IdentifierTypes = { + MSISDN: 1, + TILL_NUMBER: 2, + ORG_SHORTCODE: 4, +}; + +const responseTypes = { + COMPLETED: "Completed", + CANCELLED: "Cancelled", +}; + +const trxCodeTypes = { + BUY_GOODS: "BG", + WITHDRAW_AGENT_TILL: "WA", + PAYBILL_BUSINESS_NUMBER: "PB", + SEND_MONEY_MSISDN: "SM", + SEND_TO_BUSINESS_MSISDN: "SB", +}; + +export { CommandIDs, IdentifierTypes, responseTypes, trxCodeTypes }; diff --git a/lib/core/utils/helpers.js b/lib/core/utils/helpers.js new file mode 100644 index 0000000..b776625 --- /dev/null +++ b/lib/core/utils/helpers.js @@ -0,0 +1,337 @@ +import axios from "axios"; +import { v4 as uuidv4 } from "uuid"; +import fs from "fs"; +import path from "path"; +import crypto from "crypto"; +import globalConfigs from "./configs.js"; +import EventEmitter from "events"; + +const emitter = new EventEmitter(); + +/** + * Helper to generate a unique identifier (UUID) for the originator ID + * @return {string} - Returns a unique identifier in UUID format + */ +export function originatorID() { + return uuidv4(); +} + +/** + * Helper to generate an OAuth token for API authentication + * @return {Promise<{baseURL: string, accessToken: string}>} - Returns a promise that resolves to the access token and baseURL + * @throws {Error} - Throws an error if the token generation fails + */ +export async function generateOAuthToken() { + const { consumerKey, consumerSecret, baseUrl } = globalConfigs; + const auth = Buffer.from(`${consumerKey}:${consumerSecret}`).toString( + "base64", + ); + try { + const response = await axios.get( + `${baseUrl}/oauth/v1/generate?grant_type=client_credentials`, + { + headers: { + Authorization: `Basic ${auth}`, + "Content-Type": "application/json", + }, + }, + ); + return { accessToken: response.data.access_token, baseURL: baseUrl }; + } catch (error) { + console.error("Failed to generate OAuth token:", error.message); + throw new Error("Unable to generate OAuth token."); + } +} + +/** + * Helper to generate Lipa Na M-Pesa password and timestamp + * @param {number} shortCode - The business short code + * @return {Object} - Returns the password and timestamp + */ +export function generateMpesaCredentials(shortCode) { + const { passKey } = globalConfigs; + const timeStamp = new Date() + .toISOString() + .replace(/[^0-9]/g, "") + .slice(0, -3); + const password = Buffer.from(`${shortCode}${passKey}${timeStamp}`).toString( + "base64", + ); + return { password, timeStamp }; +} + +/** + * Encrypts the security credential using a public key from a certificate file. + * @returns {string} - The encrypted security credential encoded in base64. + * @throws {Error} - Throws an error if the encryption fails or if the certificate cannot be read. + */ +export function encryptSecurityCredential() { + const { securityCredential, certPath } = globalConfigs; + try { + const bufferToEncrypt = Buffer.from(securityCredential); + const data = fs.readFileSync(path.resolve(certPath)); + const privateKey = String(data); + + const encrypted = crypto.publicEncrypt( + { + key: privateKey, + padding: crypto.constants.RSA_PKCS1_PADDING, + }, + bufferToEncrypt, + ); + + return encrypted.toString("base64"); + } catch (error) { + console.error("Failed to encrypt security credential:", error.message); + throw new Error( + "Encryption of security credential failed. Please check the certificate path and credential.", + ); + } +} + +/** + * Handles errors encountered during API requests to the M-Pesa service. + * + * This function analyzes the error object thrown by Axios during an API + * call, providing detailed logging and user-friendly error messages based + * on the type and nature of the error. The function handles three main + * scenarios: + * + * 1. **API Error Responses**: If the error is due to a response from the + * M-Pesa API (i.e., the server responded with a status code): + * - 400: Indicates a bad request, suggesting that the parameters + * provided are invalid. + * - 401: Indicates unauthorized access, which suggests that the access + * token may be invalid. + * - 500 and above: Indicates a server error, prompting the user to + * retry the request later. + * + * 2. **Network Errors**: If the error occurs due to an issue with the + * network (i.e., no response received), it logs the error message and + * notifies the user that there may be a connection problem. + * + * 3. **Unexpected Errors**: If the error does not fall into the above + * categories, it logs the unexpected error message and throws a generic + * error message for the user. + * + * The function leverages the Axios error object, which contains + * properties like `response`, `request`, and `message` to determine the + * nature of the error. This structured approach ensures that developers + * can debug issues effectively while providing clear feedback to end users. + * + * @param {Error} error - The error object thrown by Axios during the API request. + * @throws {Error} - Throws a user-friendly error message based on the type of error encountered. + */ +export function throwErrorMessages(error) { + if (error.response) { + console.error("M-Pesa API Error:", { + status: error.response.status, + data: error.response.data, + headers: error.response.headers, + }); + + // Handle specific error responses from M-Pesa API + if (error.response.status === 400) { + throw new Error("Invalid request: Please check the parameters provided."); + } else if (error.response.status === 401) { + throw new Error( + "Unauthorized: Invalid access token. Please verify your credentials.", + ); + } else if (error.response.status >= 500) { + throw new Error("M-Pesa server error: Please try again later."); + } + } else if (error.request) { + console.error("Network Error:", error.message); + throw new Error( + "Network error: Unable to reach M-Pesa API. Please check your connection.", + ); + } else { + console.error("Unexpected Error:", error.message); + throw new Error("Unexpected error occurred. Please try again later."); + } + return null; +} + +/** + * Logs error details for advanced debugging. + * @param {Error} error - The error object caught in the catch block. + * @param {Object} context - Additional context about the API request, such as endpoint, method, and payload. + * @param {string} apiTypeMsg - Carries advanced error details for better debugging + * */ +export function logErrorDetails(error, context, apiTypeMsg) { + console.error(apiTypeMsg, { + message: error.message, + stack: error.stack, + ...(error.response && { + status: error.response.status, + data: error.response.data, + headers: error.response.headers, + }), + ...(error.request && { request: error.request }), + context, + }); +} + +/** + * Validates that a URL starts with "https://" + * @param {string} url - The URL to validate + * @param {string} name - The parameter name (for error messages) + * @throws {Error} If the URL is invalid + */ +export function validateUrl(url, name) { + if (!url || !url.startsWith("https://")) { + throw new Error(`${name} must be a valid HTTPS URL.`); + } +} + +/** + * @name validateFormatPhone + * @description Formats Kenyan phone numbers (e.g., 0711256844) to API standard (254711256844). + * @param {string} number - The phone number to be formatted. + * @returns {number} - Formatted phone number as an integer (`254XXXXXXXXX`). + * @throws {Error} - If the input is invalid or does not match the expected format. + */ +export function validateFormatPhone(number) { + if (typeof number !== "string") { + throw new Error("Invalid input: phone number must be a string."); + } + let phoneStr = String(number).trim().replace(/\D/g, ""); + if (phoneStr.length !== 10 || !phoneStr.startsWith("0")) { + throw new Error( + `Invalid phone number: must be exactly 10 digits and start with '0'}`, + ); + } + return Number(`254${phoneStr.substring(1)}`); +} + +/** + * Recursively flattens a nested object into a single-level object with + * concatenated keys separated by underscores. + * + * @param {Object} obj - The object to flatten. + * @param {string} [prefix=""] - A prefix for nested keys (used for recursion). + * @returns {Object} - A new object with flattened keys. + * + * @example + * const nestedObj = { a: { b: { c: 1 }, d: 2 }, e: 3 }; + * const flattened = flattenObject(nestedObj); + * console.log(flattened); + * // Output: { "a_b_c": 1, "a_d": 2, "e": 3 } + */ +function flattenObject(obj, prefix = "") { + return Object.keys(obj).reduce((acc, key) => { + const newKey = prefix ? `${prefix}_${key}` : key; + if (typeof obj[key] === "object" && obj[key] !== null) { + Object.assign(acc, flattenObject(obj[key], newKey)); + } else { + acc[newKey] = obj[key]; + } + return acc; + }, {}); +} + +/** + * Handles M-Pesa callback registration. + * @param {Object} appInstance - Express app instance. + * @param {string} endpoint - Api endpoint name + */ +export async function handleCallbacks(appInstance, endpoint) { + try { + if (!appInstance || typeof appInstance.post !== "function") { + throw new Error( + "handleBalanceQueryCallbacks requires a valid Express app instance.", + ); + } + + let resultRoute, + timeoutRoute = ""; + + switch (endpoint) { + case "balanceQuery": + resultRoute = "/accountbalance/result"; + timeoutRoute = "/accountbalance/queuetimeouturl"; + break; + case "c2bRegister": + resultRoute = "/confirmation/result"; + timeoutRoute = "/validation/result"; + break; + case "reversals": + resultRoute = "/Reversal/result"; + timeoutRoute = "/Reversal/queuetimeouturl"; + break; + case "mpesaSimulate": + resultRoute = "/path/result"; + timeoutRoute = ""; + break; + case "transactionStatus": + resultRoute = "/TransactionStatus/result/"; + timeoutRoute = "/TransactionStatus/queue/"; + break; + case "b2cTopUp": + resultRoute = "/path/result"; + timeoutRoute = "/path/queue"; + break; + case "b2cRequest": + resultRoute = "/b2c/result"; + timeoutRoute = "/b2c/queue"; + break; + case "businessPaybill": + resultRoute = "/path/result"; + timeoutRoute = "/path/queue"; + break; + case "taxRemittance": + resultRoute = "/remittax/result"; + timeoutRoute = "/remittax/queue"; + break; + default: + throw new Error(`Invalid endpoint provided:, ${endpoint}`); + } + appInstance.post(resultRoute, (req, res) => { + const flattenedData = flattenObject(req.body); + emitter.emit("callbackResult", flattenedData); + res.status(200).send("Callback post success"); + }); + appInstance.post(timeoutRoute, (req, res) => { + const flattenedData = flattenObject(req.body); + emitter.emit("callbackTimeout", flattenedData); + res.status(200).send("Queue post success"); + }); + console.info( + "\x1b[32m\x1b[1m%s\x1b[0m", + `Callback handler for ${endpoint} has been initialized.`, + ); + } catch (error) { + throw new Error(`Callback Error: ${error}`); + } +} + +export async function callbackTrigger(state, specialCase = false) { + if (state) { + return await new Promise((resolve) => { + const timeout = setTimeout(() => { + console.warn( + "\x1b[43m\x1b[1m\x1b[30m%s\x1b[0m", + "No callback received within the time limit.", + ); + resolve({ type: "timeout", data: {} }); + }, 15000); + + const callbackHandler = (data) => { + clearTimeout(timeout); + resolve({ type: "result", data }); + }; + + const timeoutHandler = (data) => { + clearTimeout(timeout); + resolve({ type: "timeout", data }); + }; + + if (specialCase) { + emitter.once("callbackResult", callbackHandler); + } else { + emitter.once("callbackResult", callbackHandler); + emitter.once("callbackTimeout", timeoutHandler); + } + }); + } +} diff --git a/lib/tests/.env.example b/lib/tests/.env.example new file mode 100644 index 0000000..b8cd59f --- /dev/null +++ b/lib/tests/.env.example @@ -0,0 +1,30 @@ +# ALL NECESSARY KEYS +MPESA_CONSUMER_KEY=your_consumer_key_here +MPESA_CONSUMER_SECRET=your_consumer_secret_here + +# Initiator details for API authentication +INITIATOR_NAME=your_initiator_name_here +INITIATOR_PASS=your_initiator_password_here +MPESA_SECURITY_CREDENTIAL=your_security_credential_here + +# Passkey for Lipa Na M-Pesa transactions +PASS_KEY=your_passkey_here + +# Parties involved in transactions (business shortcode and other identifiers) +PARTY_A=your_party_a_shortcode_here +PARTY_B=your_party_b_shortcode_here + +# Environment configuration +ENVIRONMENT=sandbox + +# Requester details +REQUESTER=your_requester_phone_number_here +# Phone number that will receive PIN request +MSISDN=msisdn_eg_0711225578 +# Lipa Na M-Pesa business shortcode +BUSINESS_SHORT_CODE=your_business_shortcode_here +# Account reference +ACCOUNT_REFERENCE=your_account_reference_here +# Certficate Path - Production or Sandbox +MPESA_CERT_PATH_DEV=your_dev_cert_path +MPESA_CERT_PATH_PROD=your_prod_cert_path \ No newline at end of file diff --git a/lib/tests/Paste testing - env.local b/lib/tests/Paste testing - env.local new file mode 100644 index 0000000..e69de29 diff --git a/lib/tests/apis/dummy.spec.js b/lib/tests/apis/dummy.spec.js new file mode 100644 index 0000000..a944b65 --- /dev/null +++ b/lib/tests/apis/dummy.spec.js @@ -0,0 +1,41 @@ +import { expect } from "chai"; +import sinon from "sinon"; +import { mpesa } from "../../../index.js"; +import { createOptionsForB2c } from "./utils/options.js"; + +describe("B2C Payment API - Mocked Test", function () { + this.timeout(5000); + + beforeEach(function () { + const stub = sinon.stub(mpesa, "b2cRequest").resolves({ + b2cRequestResponse: { + ResponseCode: "0", + ResponseDescription: "Request processed successfully", + OriginatorConversationID: "AG_20250224_201067702c0820b0b3b5", + }, + conditionalCallbackData: {}, + }); + + console.log("Is stub (mocking) working?", stub.isSinonProxy); // Should log true + }); + + afterEach(function () { + // Restore original function + sinon.restore(); + }); + + it("Should return a mocked B2C payment response", function (done) { + mpesa + .b2cRequest(createOptionsForB2c("https://mock-callback.url")) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody.b2cRequestResponse.ResponseCode).to.equal("0"); + console.log( + "MOCKED RESPONSE BODY:", + JSON.stringify(responseBody, null, 2), + ); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/b2c-Request.spec.js b/lib/tests/apis/main/b2c-Request.spec.js new file mode 100644 index 0000000..65ac182 --- /dev/null +++ b/lib/tests/apis/main/b2c-Request.spec.js @@ -0,0 +1,54 @@ +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { setupNgrokServer } from "../utils/server.js"; +import { createOptionsForB2c } from "../utils/options.js"; +/** + * Tests the B2C Payment API with OAuth by simulating multiple transactions in parallel. + * + * - Sets up a Ngrok server for callback handling. + * - Sends three B2C payment requests concurrently, mimicking bulk payments. + * - Verifies each response to ensure a successful transaction. + * - Logs test success for each payment. + * - Handles both valid responses and timeout scenarios. + */ + +describe("B2C Payment API with OAuth", function () { + this.timeout(24000); + let NGROK_URL, teardown; + const { b2cRequest } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer("b2cRequest", true)); + }); + + after(async function () { + await teardown(); + }); + + it("Should send multiple B2C payments in parallel and receive results or timeout callback", function (done) { + const urlToUse = NGROK_URL === "" ? "https://mock.url" : NGROK_URL; + // This simulates a bulk payment such as paying salaries + Promise.all([ + b2cRequest(createOptionsForB2c(urlToUse, "0789885845")), + b2cRequest(createOptionsForB2c(urlToUse, "0756284523")), + b2cRequest(createOptionsForB2c(urlToUse, "0741585228")), + ]) + .then(([responseBody1, responseBody2, responseBody3]) => { + [responseBody1, responseBody2, responseBody3].forEach( + (responseBody, index) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.b2cRequestResponse.ResponseCode).to.be.equal( + "0", + ); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test ${index + 1} passed successfully`, + ); + // console.log(`RESPONSE BODY ${index + 1}:`, JSON.stringify(responseBody, null, 2)); + }, + ); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/b2c-Topup.spec.js b/lib/tests/apis/main/b2c-Topup.spec.js new file mode 100644 index 0000000..7bb2524 --- /dev/null +++ b/lib/tests/apis/main/b2c-Topup.spec.js @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { setupNgrokServer } from "../utils/server.js"; +import { createOptionsForB2cAccTopUp } from "../utils/options.js"; +/** + * Tests the B2B Account Top-Up API with OAuth by simulating a single transaction. + * + * - Sets up a Ngrok server for callback handling. + * - Sends a B2C top-up request to a business account. + * - Verifies the response to ensure a successful transaction. + * - Logs test success upon receiving a valid response. + * - Handles both valid responses and timeout scenarios. + */ + +describe("B2B Account Top-Up API with OAuth", function () { + this.timeout(24000); + let NGROK_URL, teardown; + const { b2cTopUp } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer("b2cTopUp", true)); + }); + + after(async function () { + await teardown(); + }); + + it("Should simulate a B2C account top-up and receive result or timeout callback", function (done) { + b2cTopUp( + createOptionsForB2cAccTopUp( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.b2cTopUpResponse.ResponseCode).to.be.equal("0"); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/balance-Query.spec.js b/lib/tests/apis/main/balance-Query.spec.js new file mode 100644 index 0000000..278f25e --- /dev/null +++ b/lib/tests/apis/main/balance-Query.spec.js @@ -0,0 +1,48 @@ +import { expect } from "chai"; +import { setupNgrokServer } from "../utils/server.js"; +import { mpesa } from "../../../../index.js"; +import { createOptionsForBalance } from "../utils/options.js"; +/** + * Tests the Account Balance API with OAuth by simulating a balance query. + * + * - Sets up a Ngrok server for handling API callbacks. + * - Sends a request to fetch the account balance. + * - Verifies the response to confirm a successful balance retrieval. + * - Logs test success upon receiving a valid response. + * - Handles both valid responses and timeout scenarios. + */ + +describe("Account Balance API with OAuth", function () { + this.timeout(24000); + let NGROK_URL, teardown; + const { balanceQuery } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer("balanceQuery", true)); + }); + + after(async function () { + await teardown(); + }); + + it("Should fetch account balance and receive result or timeout callback", function (done) { + balanceQuery( + createOptionsForBalance( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.balanceQueryResponse.ResponseCode).to.be.equal( + "0", + ); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/business-Paybill.spec.js b/lib/tests/apis/main/business-Paybill.spec.js new file mode 100644 index 0000000..1481116 --- /dev/null +++ b/lib/tests/apis/main/business-Paybill.spec.js @@ -0,0 +1,49 @@ +import { expect } from "chai"; +import { setupNgrokServer } from "../utils/server.js"; +import { mpesa } from "../../../../index.js"; +import { createOptionsForB2bPaybill } from "../utils/options.js"; + +/** + * Tests the Account Balance API with OAuth by simulating a balance query. + * + * - Sets up a Ngrok server for handling API callbacks. + * - Sends a request to fetch the account balance. + * - Verifies the response to confirm a successful balance retrieval. + * - Logs test success upon receiving a valid response. + * - Handles both valid responses and timeout scenarios. + */ + +describe("B2B Paybill API with OAuth", function () { + this.timeout(24000); + let NGROK_URL, teardown; + const { businessPaybill } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer("businessPaybill", true)); + }); + + after(async function () { + await teardown(); + }); + + it("Should simulate a B2B paybill transaction and receive a response", function (done) { + businessPaybill( + createOptionsForB2bPaybill( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.businessPaybillResponse.ResponseCode).to.be.equal( + "1005", + ); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + /*console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2));*/ + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/c2b-Simulate.spec.js b/lib/tests/apis/main/c2b-Simulate.spec.js new file mode 100644 index 0000000..363bd51 --- /dev/null +++ b/lib/tests/apis/main/c2b-Simulate.spec.js @@ -0,0 +1,31 @@ +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { createOptionsForC2bSimulate } from "../utils/options.js"; + +/** + * Tests the C2B Simulate API with OAuth by initiating a customer-to-business transaction. + * + * - Sends a request to simulate a C2B payment. + * - Validates the response to ensure the transaction was processed successfully. + * - Logs test success upon receiving a valid response. + * - Handles both successful responses and possible timeout scenarios. + */ + +describe("C2B Simulate API with OAuth", function () { + this.timeout(28000); + const { c2bSimulate } = mpesa; + it("Should simulate a C2B transaction", function (done) { + c2bSimulate(createOptionsForC2bSimulate()) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.c2bSimulateResponse.ResponseCode).to.be.equal("0"); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/mpesa-Express.spec.js b/lib/tests/apis/main/mpesa-Express.spec.js new file mode 100644 index 0000000..e90044d --- /dev/null +++ b/lib/tests/apis/main/mpesa-Express.spec.js @@ -0,0 +1,79 @@ +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { + createOptionsForMpesaQuery, + createOptionsForMpesaSimulate +} from "../utils/options.js"; +import { setupNgrokServer } from "../utils/server.js"; +/** + * Initiates an M-Pesa Express (STK Push) simulation and then queries the status + * using the CheckoutRequestID. + * + * (Optional but recommended) - If you can manually provide the CheckoutRequestID, + * it's preferable. This setup automatically retrieves and passes it, but server + * delays can cause test failures. + * + * To retrieve the CheckoutRequestID, uncomment the console.log statement below. + */ + +describe("M-pesa express (simulate) and Query", function() { + this.timeout(15000); + let NGROK_URL, teardown; + const { mpesaSimulate, mpesaQuery } = mpesa; + + before(async function() { + ({ NGROK_URL, teardown } = await setupNgrokServer("mpesaSimulate", true)); + }); + + after(async function() { + await teardown(); + }); + it("Should initiate an M-Pesa payment then pass CheckoutRequestID to M-Pesa Query", function(done) { + mpesaSimulate( + createOptionsForMpesaSimulate( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL + ) + ) + .then((simulateResponse) => { + expect(simulateResponse).to.be.an("object"); + expect(simulateResponse?.mpesaSimulateResponse.ResponseCode).to.equal( + "0" + ); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + "Test for M-Pesa simulate passed successfully" + ); + + done() + // console.log("Simulate Response:", JSON.stringify(simulateResponse, null, 2)); + + /*return new Promise((resolve) => { + console.log( + "\x1b[45m\x1b[1m%s\x1b[0m", + " Waiting for 6 seconds before the request is transacted... " + ); + setTimeout(() => resolve(simulateResponse), 6000); + });*/ + }) + /*.then((simulateResponse) => { + return mpesaQuery( + createOptionsForMpesaQuery( + simulateResponse.mpesaSimulateResponse.CheckoutRequestID, + ), + ); + }) + .then((queryResponse) => { + expect(queryResponse).to.be.an("object"); + expect(queryResponse?.mpesaQueryResponse.ResponseCode).to.equal("0"); + + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + "Test for M-Pesa query passed successfully", + ); + // console.log("Query Response:", JSON.stringify(queryResponse, null, 2)); + + done(); + })*/ + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/qr-Generate.spec.js b/lib/tests/apis/main/qr-Generate.spec.js new file mode 100644 index 0000000..7e034c4 --- /dev/null +++ b/lib/tests/apis/main/qr-Generate.spec.js @@ -0,0 +1,31 @@ +import { expect } from "chai"; +import { mpesa } from "../../../../index.js"; +import { createOptionsForQrCode } from "../utils/options.js"; + +/** + * Tests the Generate Dynamic QR Code API. + * + * - Sends a request to generate a QR code dynamically. + * - Validates that the response is an object. + * - Logs success if the QR code generation is successful. + * - Handles potential errors or timeout scenarios. + */ + +describe("Generate Dynamic QR Code API", function () { + this.timeout(24000); + const { generateQrCode } = mpesa; + + it("Should generate a dynamic QR code successfully", function (done) { + generateQrCode(createOptionsForQrCode()) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/reversals.spec.js b/lib/tests/apis/main/reversals.spec.js new file mode 100644 index 0000000..3d8309a --- /dev/null +++ b/lib/tests/apis/main/reversals.spec.js @@ -0,0 +1,48 @@ +import { expect } from "chai"; +import { setupNgrokServer } from "../utils/server.js"; +import { createOptionsForReversals } from "../utils/options.js"; +import { mpesa } from "../../../../index.js"; + +/** + * Tests the Reversal API. + * + * - Initiates a reversal request using a provided transaction ID. + * - Verifies that the response is an object. + * - Checks if the response code indicates a successful reversal. + * - Logs success if the test passes. + * - Handles potential errors or timeout scenarios. + */ + +describe("Reversal API Test", function () { + this.timeout(28000); + let NGROK_URL, teardown; + const { reversals } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer("reversals", true)); + }); + + after(async function () { + await teardown(); + }); + + it("Should initiate a reversal and return a response", function (done) { + reversals( + createOptionsForReversals( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + "OEI2AK4Q16", + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.reversalsResponse.ResponseCode).to.be.equal("0"); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/main/transaction-status.spec.js b/lib/tests/apis/main/transaction-status.spec.js new file mode 100644 index 0000000..f46cf2e --- /dev/null +++ b/lib/tests/apis/main/transaction-status.spec.js @@ -0,0 +1,51 @@ +import { expect } from "chai"; +import { setupNgrokServer } from "../utils/server.js"; +import { mpesa } from "../../../../index.js"; +import { createOptionsForTransactionStatus } from "../utils/options.js"; +/** + * Tests the Transaction Status API. + * + * - Sends a request to retrieve the status of a transaction. + * - Verifies that the response is a valid object. + * - Ensures the response code indicates a successful transaction status check. + * - Logs success if the test passes. + * - Handles potential errors or timeout scenarios. + */ + +describe("Transaction Status API", function () { + this.timeout(24000); + let NGROK_URL, teardown; + const { transactionStatus } = mpesa; + + before(async function () { + ({ NGROK_URL, teardown } = await setupNgrokServer( + "transactionStatus", + true, + )); + }); + + after(async function () { + await teardown(); + }); + + it("Should retrieve transaction status and return a response", function (done) { + transactionStatus( + createOptionsForTransactionStatus( + NGROK_URL === "" ? "https://mock.url" : NGROK_URL, + ), + ) + .then((responseBody) => { + expect(responseBody).to.be.an("object"); + expect(responseBody?.transactStatusResponse.ResponseCode).to.be.equal( + "0", + ); + console.log( + "\x1b[35m\x1b[4m\x1b[1m%s\x1b[0m", + `Test passed successfully`, + ); + // console.log("RESPONSE BODY:", JSON.stringify(responseBody, null, 2)); + done(); + }) + .catch(done); + }); +}); diff --git a/lib/tests/apis/utils/callbacks.js b/lib/tests/apis/utils/callbacks.js new file mode 100644 index 0000000..3e4b93f --- /dev/null +++ b/lib/tests/apis/utils/callbacks.js @@ -0,0 +1,53 @@ +import { callbacks } from "../../../../index.js"; + +// Destructure all available callbackHandlers + +const { + handleB2cRequestCallbacks, + handleB2cTopUpCallbacks, + handleBalanceQueryCallbacks, + handleBusinessPaybillCallbacks, + handleC2bRegisterCallbacks, + handleTaxRemittanceCallbacks, + handleTransactStatusCallbacks, + handleReversalCallbacks, + handleMpesaSimulateCallbacks, +} = callbacks; + +// Nest all callbacks into one single exportable arrow function + +const runSingleCallbacks = async (testName, app) => { + switch (testName) { + case "balanceQuery": + await handleBalanceQueryCallbacks(app); + break; + case "transactionStatus": + await handleTransactStatusCallbacks(app); + break; + case "c2bRegister": + await handleC2bRegisterCallbacks(app); + break; + case "reversals": + await handleReversalCallbacks(app); + break; + case "mpesaSimulate": + await handleMpesaSimulateCallbacks(app); + break; + case "b2cTopUp": + await handleB2cTopUpCallbacks(app); + break; + case "b2cRequest": + await handleB2cRequestCallbacks(app); + break; + case "taxRemittance": + await handleTaxRemittanceCallbacks(app); + break; + case "businessPaybill": + await handleBusinessPaybillCallbacks(app); + break; + default: + //null + } +}; + +export { runSingleCallbacks }; diff --git a/lib/tests/apis/utils/configs.js b/lib/tests/apis/utils/configs.js new file mode 100644 index 0000000..41c2765 --- /dev/null +++ b/lib/tests/apis/utils/configs.js @@ -0,0 +1,32 @@ +import dotenv from "dotenv"; +import path from "path"; + +// Load environment variables from the .env.local file +dotenv.config({ path: path.resolve("./lib/tests/.env.local") }); + +// Destructure the necessary environment variables +const { + MPESA_INITIATOR_NAME, + MPESA_INITIATOR_PASS, + PARTY_A, + PARTY_B, + REQUESTER, + MSISDN, + BUSINESS_SHORT_CODE, + ACCOUNT_REFERENCE, +} = process.env; + +// Create an object to hold the configuration +const configs = { + initiatorName: MPESA_INITIATOR_NAME, + initiatorPass: MPESA_INITIATOR_PASS, + partyA: PARTY_A, + partyB: PARTY_B, + requester: REQUESTER, + msisdn: MSISDN, + businessShortCode: BUSINESS_SHORT_CODE, + accountRef: ACCOUNT_REFERENCE, +}; + +// Export the configuration object +export default configs; diff --git a/lib/tests/apis/utils/options.js b/lib/tests/apis/utils/options.js new file mode 100644 index 0000000..9e97779 --- /dev/null +++ b/lib/tests/apis/utils/options.js @@ -0,0 +1,127 @@ +import configs from "./configs.js"; +import { + CommandIDs, + IdentifierTypes, + responseTypes, + trxCodeTypes, +} from "../../../core/utils/constants.js"; + +export function createOptionsForQrCode() { + return { + merchantName: "TEST-Supermarket", + refNo: "xewr34fer4t", + amount: 2000, + trxCode: trxCodeTypes.BUY_GOODS, + cpi: "174379", + size: "300", + }; +} + +export function createOptionsForMpesaQuery(passRequestIdHere) { + return { + businessShortCode: parseInt(configs.businessShortCode), + checkoutRequestId: `${passRequestIdHere}`, + }; +} + +export function createOptionsForB2c(NGROK_URL, msisdn) { + return { + partyA: parseInt(configs.partyA), + partyB: msisdn, + initiatorName: configs.initiatorName, + amount: parseInt("1000"), + commandId: CommandIDs.SALARY_PAYMENT, + QueueTimeOutURL: `${NGROK_URL}/b2c/queue`, + resultURL: `${NGROK_URL}/b2c/result`, + occasion: "TEST", + remarks: "TEST", + }; +} + +export function createOptionsForC2bSimulate() { + return { + shortCode: parseInt(configs.partyA), + msisdn: configs.msisdn, + amount: parseInt("100"), + billRefNumber: "invoice008", + }; +} + +export function createOptionsForBalance(NGROK_URL) { + return { + identifierType: IdentifierTypes.TILL_NUMBER, + partyA: parseInt(configs.partyA), + initiator: configs.initiatorName, + QueueTimeOutURL: `${NGROK_URL}/accountbalance/queuetimeouturl`, + resultURL: `${NGROK_URL}/accountbalance/result`, + remarks: "TEST", + }; +} + +export function createOptionsForMpesaSimulate(NGROK_URL) { + return { + partyB: parseInt(configs.partyB), + partyA: configs.msisdn, + phoneNumber: configs.msisdn, + transactionType: "CustomerPayBillOnline", + transactionDesc: "TEST", + amount: 1, + callbackURL: `${NGROK_URL}/path/result`, + accountRef: configs.accountRef, + }; +} + +export function createOptionsForReversals(NGROK_URL, transId) { + return { + receiverParty: parseInt(configs.partyA), + initiator: configs.initiatorName, + transactionId: transId, + amount: parseInt("100"), + QueueTimeOutURL: `${NGROK_URL}/Reversal/queuetimeouturl`, + resultURL: `${NGROK_URL}/Reversal/result`, + remarks: "TEST", + occasion: "TEST", + }; +} + +export function createOptionsForTransactionStatus(NGROK_URL) { + return { + identifierType: parseInt(IdentifierTypes.ORG_SHORTCODE), + OriginatorConversationID: "AG_20190826_0000777ab7d848b9e721", + transactionId: "OEI2AK4Q16", + initiator: configs.initiatorName, + partyA: parseInt(configs.partyA), + resultURL: `${NGROK_URL}/TransactionStatus/result/`, + QueueTimeOutURL: `${NGROK_URL}/TransactionStatus/queue/`, + remarks: "TEST", + occasion: "TEST", + }; +} + +export function createOptionsForB2cAccTopUp(NGROK_URL) { + return { + accountReference: parseInt(configs.accountRef), + partyA: parseInt(configs.partyA), + partyB: parseInt(configs.partyB), + requester: parseInt(configs.requester), //optional + initiator: configs.initiatorName, + amount: parseInt("100"), + resultURL: `${NGROK_URL}/path/result`, + QueueTimeOutURL: `${NGROK_URL}/path/queue`, + remarks: "TEST", + }; +} + +export function createOptionsForB2bPaybill(NGROK_URL) { + return { + initiator: configs.initiatorName, + partyA: parseInt(configs.partyA), + partyB: parseInt(configs.partyB), + amount: parseInt("100"), + accountReference: parseInt(configs.accountRef), + requester: parseInt(configs.requester), //optional + resultURL: `${NGROK_URL}/path/result`, + QueueTimeOutURL: `${NGROK_URL}/path/queue`, + remarks: "TEST", + }; +} diff --git a/lib/tests/apis/utils/server.js b/lib/tests/apis/utils/server.js new file mode 100644 index 0000000..35cab43 --- /dev/null +++ b/lib/tests/apis/utils/server.js @@ -0,0 +1,57 @@ +import http from "http"; +import ngrok from "ngrok"; +import express from "express"; +import { runSingleCallbacks } from "./callbacks.js"; + +// Initialize Express app +const app = express(); +app.use(express.json()); + +async function setupNgrokServer(name, disabled = true) { + if (disabled) { + console.info( + "\x1b[43m\x1b[30m\x1b[1m%s\x1b[0m", + " Ngrok server will not be initiated ", + ); + return { + NGROK_URL: "", + teardown: async () => {}, + }; + } + // Create and start the HTTP server on a random available port + const SERVER = http.createServer(app); + SERVER.listen(0); + const port = SERVER.address().port; + + // Start ngrok tunnel + const NGROK_URL = await ngrok.connect(port); + + // Initialize callback handlers + await runSingleCallbacks(name, app); + + // Teardown function to clean up resources + async function teardown() { + console.info("\x1b[43m\x1b[30m\x1b[1m%s\x1b[0m", "Closing exposed port"); + try { + await ngrok.disconnect(); + await new Promise((resolve, reject) => { + SERVER.close((err) => (err ? reject(err) : resolve())); + }); + console.log("\x1b[32m\x1b[1m%s\x1b[0m", "Server closed gracefully"); + } catch (err) { + console.error( + "\x1b[31m\x1b[1m%s\x1b[0m", + "Error while closing server:", + err, + ); + } finally { + setTimeout(() => { + process.exit(1); + }, 2000); + } + } + + return { NGROK_URL, teardown }; +} + +export { setupNgrokServer }; diff --git a/keys/sandbox-cert.cer b/lib/tests/certs/SandboxCertificate.cer similarity index 98% rename from keys/sandbox-cert.cer rename to lib/tests/certs/SandboxCertificate.cer index 49ba2f1..45eac6e 100644 --- a/keys/sandbox-cert.cer +++ b/lib/tests/certs/SandboxCertificate.cer @@ -34,4 +34,4 @@ KMmJCY3sXxFHs5ilNXo8YavgRLpxJxdZMkiUIVuVaBanXkz9/nMriiJJwwcMPjUV w4THLy9rDmUIasC8GDdRcVM8xDOVQD/Pt5qlx/LSbTNe2fekhTLFIGYXJVz2rcsj k1BfG7P3pXnsPAzu199UZnqhEF+y/0/nNpf3ftHZjfX6Ws+dQuLoDN6pIl8qmok9 9E/EAgL1zOIzFvCRYlnjKdnsuqL1sIYFBlv3oxo6W1O+X9IZ ------END CERTIFICATE----- +-----END CERTIFICATE----- \ No newline at end of file diff --git a/package.json b/package.json index aa90eb4..54fc812 100644 --- a/package.json +++ b/package.json @@ -1,50 +1,72 @@ { "name": "mpesa-node", "version": "0.1.3", - "description": "Node M-Pesa Library", + "description": "M-Pesa Library for Node.js using REST API", + "main": "./index.js", + "types": "./index.d.ts", "repository": { "type": "git", "url": "https://github.com/safaricom/mpesa-node-library" }, - "main": "src/m-pesa.js", + "type": "module", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.js", + "default": "./index.js" + } + }, "dependencies": { - "axios": "^0.19.0" + "axios": "^1.5.0", + "dotenv": "^16.4.7", + "express": "^4.21.2", + "ngrok": "^5.0.0-beta.2", + "uuid": "^11.0.5" }, "devDependencies": { - "body-parser": "^1.18.2", - "dotenv": "^5.0.1", - "expect.js": "^0.3.1", - "express": "^4.16.3", - "got": "^8.3.0", - "jsdoc": "^3.5.5", - "mocha": "^5.0.1", - "ngrok": "^3.0.0", - "nyc": "^12.0.2", - "standard": "^11.0.0", - "supertest": "^3.0.0" + "@babel/cli": "^7.25.9", + "@babel/core": "^7.25.9", + "@babel/polyfill": "7.12.1", + "@babel/preset-env": "^7.25.9", + "@babel/register": "^7.25.9", + "chai": "^5.1.2", + "eslint": "^9.19.0", + "html-minifier-terser": "^7.2.0", + "jsdoc": "^4.0.4", + "minami": "^1.2.3", + "mocha": "^11.1.0", + "prettier": "^3.3.3", + "sinon": "^19.0.2", + "taffydb": "^2.7.3", + "typescript-eslint": "^8.22.0" }, "scripts": { - "test": "npm run test-unit && npm run test-integration", - "test-unit": "mocha tests/unit/*.test.js", - "test-integration": "nyc --reporter=text mocha --exit tests/integrations/*.js" + "test": "mocha --require @babel/polyfill --require @babel/register lib/tests/apis/main/**/*.spec.js", + "format": "prettier --write .", + "docs": "jsdoc -c jsdoc.json" }, "keywords": [ "mpesa", - "mpesa-node", - "mpesa-api" + "mpesa node js", + "mpesa api", + "daraja api", + "mpesa integration", + "mpesa sdk", + "mpesa node library", + "mpesa node module", + "safaricom mpesa", + "mpesa payment gateway" ], - "standard": { - "globals": [ - "describe", - "context", - "before", - "beforeEach", - "after", - "afterEach", - "it", - "expect" - ] - }, "author": "Geoffrey Mureithi", - "license": "MIT" + "license": "Apache-2.0", + "contributors": [ + { + "name": "Samm waturu", + "email": "muiruri.samwel@outlook.com" + }, + { + "name": "Dgatere", + "email": "" + } + ] } diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 0000000..cf20b0d --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,30 @@ +--- +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +#Disable inspections +#exclude: +# - name: +# paths: +# - + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-js:2024.3 diff --git a/src/endpoints/account-balance.js b/src/endpoints/account-balance.js deleted file mode 100644 index 6dc2ff3..0000000 --- a/src/endpoints/account-balance.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * AccountBalance - Use this API to enquire the balance on an M-Pesa BuyGoods (Till Number) - * @name AccountBalance - * @function - * @see {@link https://developer.safaricom.co.ke/account-balance/apis/post/query|Account Balance Request} - * @param {integer} shortCode The organisation shortCode - * @param {integer} idType Type of organization receiving the transaction - * @param {String} queueUrl The path that stores information of a time out transaction - * @param {String} resultUrl The path that stores information of transaction - * @param {String} [remarks='Checking account balance'] Comments that are sent along with the transaction. - * @param {String} [initiator=null] The name of Initiator to initiating the request - * @param {String} [commandId='AccountBalance'] Takes only 'AccountBalance' CommandID - * @return {Promise} This returns a promise that resolves to the account balance - */ -module.exports = async function accountBalance (shortCode, idType, queueUrl, resultUrl, remarks = 'Checking account balance', initiator = null, commandId = 'AccountBalance') { - const securityCredential = this.security() - const req = await this.request() - return req.post('/mpesa/accountbalance/v1/query', { - 'Initiator': initiator || this.configs.initiatorName, - 'SecurityCredential': securityCredential, - 'CommandID': commandId, - 'PartyA': shortCode, - 'IdentifierType': idType, - 'Remarks': remarks, - 'QueueTimeOutURL': queueUrl, - 'ResultURL': resultUrl - }) -} diff --git a/src/endpoints/b2b.js b/src/endpoints/b2b.js deleted file mode 100644 index 866793c..0000000 --- a/src/endpoints/b2b.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * B2B Request - * @name B2BRequest - * @function - * @see {@link https://developer.safaricom.co.ke/b2b/apis/post/paymentrequest|Account Balance Request} - * @description - Use this api to transit Mpesa Transaction from one company to another. - * @param {number} senderParty Organization Sending the transaction - * @param {number} receiverParty Organization Receiving the funds - * @param {number} amount The amount been transacted - * @param {string} queueUrl The path that stores information of time out transactions - * @param {string} resultUrl The path that receives results from M-Pesa. - * @param {number} [senderType=4] Type of organization sending the transaction[ default Shortcode] - * @param {number} [receiverType=4] Type of organization receiving the transaction [ default Shortcode] - * @param {string} [initiator=null] This is the credential/username used to authenticate the transaction request. - * @param {String} [commandId='BusinessToBusinessTransfer'] The command id used to carry out a B2B payment[BusinessPayBill,BusinessBuyGoods, DisburseFundsToBusiness, BusinessToBusinessTransfer, MerchantToMerchantTransfer] - * @param {string} [accountRef=null] Account Reference mandatory for "BussinessPaybill" CommandID - * @param {String} [remarks='B2B Request'] Comments that are sent along with the transaction. - * @return {Promise} - */ -module.exports = async function (senderParty, receiverParty, amount, queueUrl, resultUrl, senderType = 4, receiverType = 4, initiator = null, commandId = 'BusinessToBusinessTransfer', accountRef = null, remarks = 'B2B Request') { - const req = await this.request() - const securityCredential = this.security() - return req.post('/mpesa/b2b/v1/paymentrequest', { - 'Initiator': initiator || this.configs.initiatorName, - 'SecurityCredential': securityCredential, - 'CommandID': commandId, - 'SenderIdentifierType': senderType, - 'RecieverIdentifierType': receiverType, - 'Amount': amount, - 'PartyA': senderParty, - 'PartyB': receiverParty, - 'AccountReference': accountRef, - 'Remarks': remarks, - 'QueueTimeOutURL': queueUrl, - 'ResultURL': resultUrl - }) -} diff --git a/src/endpoints/b2c.js b/src/endpoints/b2c.js deleted file mode 100644 index f42a6b5..0000000 --- a/src/endpoints/b2c.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * B2C Payment Request - * @name B2CRequest - * @function - * @description Use this API to transact between an M-Pesa short code to a phone number registered on M-Pesa. - * @see {@link https://developer.safaricom.co.ke/b2c/apis/post/paymentrequest|B2C Payment Request} - * @param {number} senderParty Organization /MSISDN sending the transaction - * @param {number} receiverParty MSISDN receiving the transaction - * @param {number} amount The amount being transacted - * @param {string} queueUrl The path that stores information of time out transaction - * @param {string} resultUrl The path that stores information of transaction - * @param {string} [commandId='BusinessPayment'] Unique command for each transaction type [SalaryPayment|BusinessPayment|PromotionPayment] - * @param {string} [initiatorName=null] The name of the initiator initiating the request - * @param {String} [remarks='B2C Payment'] Comments that are sent along with the transaction. - * @param {string} occasion - * @return {Promise} - */ -module.exports = async function (senderParty, receiverParty, amount, queueUrl, resultUrl, commandId = 'BusinessPayment', initiatorName = null, remarks = 'B2C Payment', occasion) { - const securityCredential = this.security() - const req = await this.request() - return req.post('/mpesa/b2c/v1/paymentrequest', { - 'InitiatorName': initiatorName || this.configs.initiatorName, - 'SecurityCredential': securityCredential, - 'CommandID': commandId, - 'Amount': amount, - 'PartyA': senderParty, - 'PartyB': receiverParty, - 'Remarks': remarks, - 'QueueTimeOutURL': queueUrl, - 'ResultURL': resultUrl, - 'Occasion': occasion - }) -} diff --git a/src/endpoints/c2b-register.js b/src/endpoints/c2b-register.js deleted file mode 100644 index 1af3e43..0000000 --- a/src/endpoints/c2b-register.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * C2B Register URL - * @name C2BRegister - * @function - * @description Use this API to register validation and confirmation URLs on M-Pesa - * @see {@link https://developer.safaricom.co.ke/c2b/apis/post/registerurl| C2B Register URL} - * @param {string} confirmationUrl Validation URL for the client - * @param {string} validationUrl Confirmation URL for the client - * @param {number} [shortCode=null] The short code of the organization. - * @param {string} [responseType='Completed'] Default response type for timeout. Incase a tranaction times out, Mpesa will by default Complete or Cancel the transaction - * @return {Promise} - */ -module.exports = async function (confirmationUrl, validationUrl, shortCode = null, responseType = 'Completed') { - const req = await this.request() - return req.post('/mpesa/c2b/v1/registerurl', { - 'ShortCode': shortCode || this.configs.shortCode, - 'ResponseType': responseType, - 'ConfirmationURL': confirmationUrl, - 'ValidationURL': validationUrl - }) -} diff --git a/src/endpoints/c2b-simulate.js b/src/endpoints/c2b-simulate.js deleted file mode 100644 index 6b5bbef..0000000 --- a/src/endpoints/c2b-simulate.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * C2B Simulate Transaction - * @name C2BSimulate - * @function - * @description Use this API to simulate a C2B transaction - * @see {@link https://developer.safaricom.co.ke/c2b/apis/post/simulate | C2B Simulate Transaction } - * @param {number} msisdn Phone number (msisdn) initiating the transaction - * @param {number} amount The amount being transacted - * @param {string} billRefNumber Bill Reference Number - * @param {string} [commandId='CustomerPayBillOnline'] Unique command for each transaction type. For C2B dafult - * @param {number} [shortCode=null] Short Code receiving the amount being transacted - * @return {Promise} - */ -module.exports = async function (msisdn, amount, billRefNumber, commandId = 'CustomerPayBillOnline', shortCode = null) { - const req = await this.request() - return req.post('/mpesa/c2b/v1/simulate', { - 'ShortCode': shortCode || this.configs.shortCode, - 'CommandID': commandId, - 'Amount': amount, - 'Msisdn': msisdn, - 'BillRefNumber': billRefNumber - }) -} diff --git a/src/endpoints/index.js b/src/endpoints/index.js deleted file mode 100644 index 2f13b39..0000000 --- a/src/endpoints/index.js +++ /dev/null @@ -1,23 +0,0 @@ -const accountBalance = require('./account-balance') -const b2b = require('./b2b') -const b2c = require('./b2c') -const c2bRegister = require('./c2b-register') -const c2bSimulate = require('./c2b-simulate') -const lipaNaMpesaOnline = require('./lipa-na-mpesa-online') -const lipaNaMpesaQuery = require('./lipa-na-mpesa-query') -const oAuth = require('./oauth') -const reversal = require('./reversal') -const transactionStatus = require('./transaction-status') - -module.exports = { - accountBalance, - b2b, - b2c, - c2bRegister, - c2bSimulate, - lipaNaMpesaOnline, - lipaNaMpesaQuery, - reversal, - transactionStatus, - oAuth -} diff --git a/src/endpoints/lipa-na-mpesa-online.js b/src/endpoints/lipa-na-mpesa-online.js deleted file mode 100644 index 57057d2..0000000 --- a/src/endpoints/lipa-na-mpesa-online.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Lipa Na M-Pesa Online Payment API - * @name lipaNaMpesaOnline - * @description Use this API to initiate online payment on behalf of a customer. - * @see {@link https://developer.safaricom.co.ke/lipa-na-m-pesa-online/apis/post/stkpush/v1/processrequest|Lipa Na M-Pesa Online Payment API } - * @param {number} senderMsisdn The MSISDN sending the funds - * @param {number} amount The amount to be transacted - * @param {string} callbackUrl Call Back URL - * @param {string} accountRef Account Reference - * @param {string} [transactionDesc='Lipa na mpesa online'] any string of less then 20 characters - * @param {string} [transactionType='CustomerPayBillOnline'] The transaction type to be used for the request 'CustomerPayBillOnline' - * @param {number} [shortCode=null] The organization shortcode used to receive the transaction - * @param {string} [passKey=null] Lipa na mpesa passKey - * @return {Promise} - */ -module.exports = async function (senderMsisdn, amount, callbackUrl, accountRef, transactionDesc = 'Lipa na mpesa online', transactionType = 'CustomerPayBillOnline', shortCode = null, passKey = null) { - const _shortCode = shortCode || this.configs.lipaNaMpesaShortCode - const _passKey = passKey || this.configs.lipaNaMpesaShortPass - const timeStamp = (new Date()).toISOString().replace(/[^0-9]/g, '').slice(0, -3) - const password = Buffer.from(`${_shortCode}${_passKey}${timeStamp}`).toString('base64') - const req = await this.request() - return req.post('/mpesa/stkpush/v1/processrequest', { - 'BusinessShortCode': _shortCode, - 'Password': password, - 'Timestamp': timeStamp, - 'TransactionType': transactionType, - 'Amount': amount, - 'PartyA': senderMsisdn, - 'PartyB': _shortCode, - 'PhoneNumber': senderMsisdn, - 'CallBackURL': callbackUrl, - 'AccountReference': accountRef, - 'TransactionDesc': transactionDesc - }) -} diff --git a/src/endpoints/lipa-na-mpesa-query.js b/src/endpoints/lipa-na-mpesa-query.js deleted file mode 100644 index c74f174..0000000 --- a/src/endpoints/lipa-na-mpesa-query.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Lipa Na M-Pesa Query Request API - * @name LipaNaMpesaQuery - * @description Use this API to check the status of a Lipa Na M-Pesa Online Payment. - * @param {string} checkoutRequestId Checkout RequestID - * @param {number} [shortCode=null] Business Short Code - * @param {number} [timeStamp=null] timeStamp - * @param {string} [passKey=null] lipaNaMpesa Pass Key - * @return {Promise} - */ -module.exports = async function (checkoutRequestId, shortCode = null, passKey = null) { - const _shortCode = shortCode || this.configs.lipaNaMpesaShortCode - const _passKey = passKey || this.configs.lipaNaMpesaShortPass - const timeStamp = (new Date()).toISOString().replace(/[^0-9]/g, '').slice(0, -3) - const password = Buffer.from(`${_shortCode}${_passKey}${timeStamp}`).toString('base64') - const req = await this.request() - return req.post('/mpesa/stkpushquery/v1/query', { - 'BusinessShortCode': _shortCode, - 'Password': password, - 'Timestamp': timeStamp, - 'CheckoutRequestID': checkoutRequestId - }) -} diff --git a/src/endpoints/oauth.js b/src/endpoints/oauth.js deleted file mode 100644 index af0301b..0000000 --- a/src/endpoints/oauth.js +++ /dev/null @@ -1,10 +0,0 @@ -const axios = require('axios') -module.exports = function (consumerKey, consumerSecret, baseURL = null) { - const auth = Buffer.from(consumerKey + ':' + consumerSecret).toString('base64') - return axios.get((baseURL || this.baseURL) + '/oauth/v1/generate?grant_type=client_credentials', { - headers: { - 'Authorization': 'Basic ' + auth, - 'content-type': 'application/json' - } - }) -} diff --git a/src/endpoints/reversal.js b/src/endpoints/reversal.js deleted file mode 100644 index 4c97d8e..0000000 --- a/src/endpoints/reversal.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Reversal Request - * @name ReversalRequest - * @description Transaction Reversal API reverses a M-Pesa transaction. - * @function - * @see {@link https://developer.safaricom.co.ke/reversal/apis/post/request| Reversal Request} - * @param {string} transactionId The transaction id for reversal eg LKXXXX1234 - * @param {string} queueUrl The path that stores information of time out transaction - * @param {string} resultUrl The path that stores information of transaction - * @param {string} [shortCode=null] Organization receiving the transaction - * @param {String} [remarks='Reversal'] Comments that are sent along with the transaction. - * @param {String} [occasion='Reversal'] Optional Parameter - * @param {[type]} [initiator=null] The name of Initiator to initiating the request - * @param {String} [receiverIdType='11'] Type of organization receiving the transaction - * @param {String} [commandId='TransactionReversal'] Takes only 'TransactionReversal' Command id - * @return {Promise} - */ -module.exports = async function (transactionId, amount, queueUrl, resultUrl, shortCode = null, remarks = 'Reversal', occasion = 'Reversal', initiator = null, receiverIdType = '11', commandId = 'TransactionReversal') { - const securityCredential = this.security() - const req = await this.request() - return req.post('/mpesa/reversal/v1/request', { - 'Initiator': initiator || this.configs.initiatorName, - 'SecurityCredential': securityCredential, - 'CommandID': commandId, - 'TransactionID': transactionId, - 'Amount': amount, - 'ReceiverParty': shortCode || this.configs.shortCode, - 'RecieverIdentifierType': receiverIdType, - 'ResultURL': resultUrl, - 'QueueTimeOutURL': queueUrl, - 'Remarks': remarks, - 'Occasion': occasion - }) -} diff --git a/src/endpoints/transaction-status.js b/src/endpoints/transaction-status.js deleted file mode 100644 index c4542e2..0000000 --- a/src/endpoints/transaction-status.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Transaction Status Request - * @name TransactionStatus - * @description Use this api to check the transaction status. - * @function - * @see {@link https://developer.safaricom.co.ke/transaction-status/apis/post/query| Transaction Status Request } - * @param {string} transactionId Unique identifier to identify a transaction on M-Pesa - * @param {number} receiverParty Organization/MSISDN receiving the transaction - * @param {number} idType Type of organization receiving the transaction - * @param {string} queueUrl The path that stores information of time out transaction - * @param {string} resultUrl The path that stores information of transaction - * @param {String} [remarks='TransactionReversal'] Comments that are sent along with the transaction - * @param {String} [occasion='TransactionReversal'] Optional Parameter - * @param {[type]} [initiator=null] The name of Initiator to initiating the request - * @param {String} [commandId='TransactionStatusQuery'] Takes only 'TransactionStatusQuery' command id - * @return {Promise} - */ -module.exports = async function (transactionId, receiverParty, idType, queueUrl, resultUrl, remarks = 'TransactionReversal', occasion = 'TransactionReversal', initiator = null, commandId = 'TransactionStatusQuery') { - const securityCredential = this.security() - const req = await this.request() - return req.post('/mpesa/transactionstatus/v1/query', { - 'Initiator': initiator || this.configs.initiatorName, - 'SecurityCredential': securityCredential, - 'CommandID': commandId, - 'TransactionID': transactionId, - 'PartyA': receiverParty, - 'IdentifierType': idType, - 'ResultURL': resultUrl, - 'QueueTimeOutURL': queueUrl, - 'Remarks': remarks, - 'Occasion': occasion - }) -} diff --git a/src/helpers/index.js b/src/helpers/index.js deleted file mode 100644 index cd36709..0000000 --- a/src/helpers/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const request = require('./request') -const security = require('./security') - -module.exports = { - request, - security -} diff --git a/src/helpers/request.js b/src/helpers/request.js deleted file mode 100644 index a9728f9..0000000 --- a/src/helpers/request.js +++ /dev/null @@ -1,13 +0,0 @@ -const axios = require('axios') -module.exports = async function (_baseURL = null) { - const credentials = await this.oAuth() - const instance = axios.create({ - baseURL: _baseURL || this.baseURL, - timeout: 5000, - headers: { - 'Authorization': 'Bearer ' + credentials.data['access_token'], - 'Content-Type': 'application/json' - } - }) - return instance -} diff --git a/src/helpers/security.js b/src/helpers/security.js deleted file mode 100644 index 1e9f258..0000000 --- a/src/helpers/security.js +++ /dev/null @@ -1,15 +0,0 @@ -const fs = require('fs') -const path = require('path') -const crypto = require('crypto') - -module.exports = (certPath, shortCodeSecurityCredential) => { - const bufferToEncrypt = Buffer.from(shortCodeSecurityCredential) - const data = fs.readFileSync(path.resolve(certPath)) - const privateKey = String(data) - const encrypted = crypto.publicEncrypt({ - key: privateKey, - padding: crypto.constants.RSA_PKCS1_PADDING - }, bufferToEncrypt) - const securityCredential = encrypted.toString('base64') - return securityCredential -} diff --git a/src/m-pesa.js b/src/m-pesa.js deleted file mode 100644 index 36adb91..0000000 --- a/src/m-pesa.js +++ /dev/null @@ -1,95 +0,0 @@ -const { - accountBalance, - b2b, - b2c, - c2bRegister, - c2bSimulate, - lipaNaMpesaOnline, - lipaNaMpesaQuery, - oAuth, - reversal, - transactionStatus -} = require('./endpoints') -const { - request, - security -} = require('./helpers') - -/** - * Class representing the Mpesa instance - */ -class Mpesa { - /** - * Introduce Mpesa Configuration - * @constructor - * @param {Object} [config={}] The Configuration to use for mPesa - */ - constructor (config = {}) { - if (!config.consumerKey) throw new Error('Consumer Key is Missing') - if (!config.consumerSecret) throw new Error('Consumer Secret is Missing') - this.configs = { ...config } - this.enviroment = config.environment === 'production' ? 'production' : 'sandbox' - this.request = request.bind(this) - this.security = () => { - return security(this.configs.certPath, this.configs.securityCredential) - } - this.baseURL = `https://${this.enviroment === 'production' ? 'api' : 'sandbox'}.safaricom.co.ke` - } - - /** - * AccountBalance via instance - * @borrows AccountBalance as accountBalanceCall - */ - accountBalance () { - return accountBalance.bind(this)(...arguments) - } - - /** - * B2B Request via instance - * @name b2bCall - */ - b2b () { - return b2b.bind(this)(...arguments) - } - - /** - * B2C Request - * @borrows B2CRequest as b2c - */ - b2c () { - return b2c.bind(this)(...arguments) - } - - c2bRegister () { - return c2bRegister.bind(this)(...arguments) - } - c2bSimulate () { - if(this.enviroment === 'production'){ - throw new Error('Cannot call C2B simulate in production.') - } - return c2bSimulate.bind(this)(...arguments) - } - - lipaNaMpesaOnline () { - return lipaNaMpesaOnline.bind(this)(...arguments) - } - - lipaNaMpesaQuery () { - return lipaNaMpesaQuery.bind(this)(...arguments) - } - - oAuth () { - const { consumerKey, consumerSecret } = this.configs - return oAuth.bind(this)(consumerKey, consumerSecret) - } - - reversal () { - return reversal.bind(this)(...arguments) - } - - transactionStatus () { - return transactionStatus.bind(this)(...arguments) - } -} - -module.exports = Mpesa \ No newline at end of file diff --git a/tests/helpers/app.js b/tests/helpers/app.js deleted file mode 100644 index 629404e..0000000 --- a/tests/helpers/app.js +++ /dev/null @@ -1,119 +0,0 @@ -/*** - * This is a sample express of how to handle callbacks - * @see {@link https://github.com/safaricom/mpesa_listener| Mpesa Lister Example} - */ - -const express = require('express') -const app = express() -const bodyParser = require('body-parser') - -const emitter = require('./callbacksemitter') - -app.use(bodyParser.json()) -app.get('/', (req, res) => { - emitter.emit('hello', 'From CallbacksEmitter') - res.send('Hello World!') -}) -// AccountBalance -app.post('/accountbalance/timeout', (req, res) => { - emitter.emit('accountBalanceTimeout', { simulation: true, success: true }) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/accountbalance/success', (req, res) => { - emitter.emit('accountBalanceCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) - -// B2B Call -app.post('/b2b/timeout', (req, res) => { - emitter.emit('b2bTimeout', { simulation: true, success: true }) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/b2b/success', (req, res) => { - emitter.emit('b2bSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -// B2C Call -app.post('/b2c/timeout', (req, res) => { - emitter.emit('b2cTimeout', { simulation: true, success: true }) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/b2c/success', (req, res) => { - emitter.emit('b2cSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -// C2B -app.post('/c2b/confirmation', (req, res) => { - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/c2b/success', (req, res) => { - emitter.emit('c2bSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) - -// Lipa na mpesa -app.post('/lipanampesa/success', (req, res) => { - emitter.emit('lipaNaMpesaOnlineSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) - -// Reversal -app.post('/reversal/timeout', (req, res) => { - emitter.emit('reversalTimeout', { simulation: true, success: true }) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/reversal/success', (req, res) => { - emitter.emit('reversalSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) - -// Transaction Status -app.post('/transactionstatus/timeout', (req, res) => { - emitter.emit('transactionStatusTimeout', { simulation: true, success: true }) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) -app.post('/transactionstatus/success', (req, res) => { - emitter.emit('transactionStatusSuccessCallback', req.body) - res.json({ - 'ResponseCode': '00000000', - 'ResponseDesc': 'success' - }) -}) - -module.exports = app diff --git a/tests/helpers/callbacksemitter.js b/tests/helpers/callbacksemitter.js deleted file mode 100644 index 84fa3fd..0000000 --- a/tests/helpers/callbacksemitter.js +++ /dev/null @@ -1,9 +0,0 @@ -const util = require('util') -const events = require('events') -function CallbacksEmitter () { - events.EventEmitter.call(this) -} - -util.inherits(CallbacksEmitter, events.EventEmitter) - -module.exports = new CallbacksEmitter() diff --git a/tests/helpers/instance.js b/tests/helpers/instance.js deleted file mode 100644 index 97aeb2f..0000000 --- a/tests/helpers/instance.js +++ /dev/null @@ -1,25 +0,0 @@ -const path = require('path') -const Mpesa = require('../.././src/m-pesa') -require('dotenv').config({path: path.resolve('tests/helpers/tests.env')}) -const { - CONSUMER_KEY, - CONSUMER_SECRET, - SHORTCODE, - INITIATOR_NAME, - LIPA_NA_MPESA_SHORTCODE, - LIPA_NA_MPESA_SHORTPASS, - SECURITY_CREDENTIAL -} = process.env -const testInstance = new Mpesa({ - consumerKey: CONSUMER_KEY, - consumerSecret: CONSUMER_SECRET, - environment: 'sandbox', - shortCode: SHORTCODE, - initiatorName: INITIATOR_NAME, - lipaNaMpesaShortCode: LIPA_NA_MPESA_SHORTCODE, - lipaNaMpesaShortPass: LIPA_NA_MPESA_SHORTPASS, - securityCredential: SECURITY_CREDENTIAL, - certPath: path.resolve('keys/sandbox-cert.cer') -}) - -module.exports = testInstance diff --git a/tests/helpers/ngrok.js b/tests/helpers/ngrok.js deleted file mode 100644 index b6eed97..0000000 --- a/tests/helpers/ngrok.js +++ /dev/null @@ -1,23 +0,0 @@ -const http = require('http') -const ngrok = require('ngrok') -function ngrokify (server) { - if (typeof server === 'function') server = http.createServer(server) - - // let ngroked = Object.create(server) - let ngrokURL - - server.once('close', function () { - console.log('Closing time :)') - ngrokURL && ngrok.disconnect(ngrokURL) - }) - - let addr = server.address() - if (!addr) server.listen(0) - addr = server.address() - console.log('Using Port ' + addr.port) - return ngrok.connect(addr.port).then(function (url) { - ngrokURL = url - return url - }) -} -module.exports = ngrokify diff --git a/tests/helpers/tests.env b/tests/helpers/tests.env deleted file mode 100644 index 9f0f960..0000000 --- a/tests/helpers/tests.env +++ /dev/null @@ -1,7 +0,0 @@ -CONSUMER_KEY = OT13kmfq1I8GcD2D4JIcyrHO7C3IAM81 -CONSUMER_SECRET= nxKU4f4Zq6h1urLD -SHORTCODE = 600111 -INITIATOR_NAME = testapi111 -LIPA_NA_MPESA_SHORTCODE = 174379 -LIPA_NA_MPESA_SHORTPASS = bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919 -SECURITY_CREDENTIAL = Safaricom111! diff --git a/tests/integrations/_before.test.js b/tests/integrations/_before.test.js deleted file mode 100644 index 7906f21..0000000 --- a/tests/integrations/_before.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const app = require('.././helpers/app') -const ngrokify = require('.././helpers/ngrok') -const ngrok = require('ngrok') - -before(async function () { - this.timeout(15000) - console.log('Setting up the callback server') - await ngrok.disconnect() - global.NGROK_URL = await ngrokify(app) - console.log('Connected to ' + global.NGROK_URL) -}) diff --git a/tests/integrations/_init.js b/tests/integrations/_init.js deleted file mode 100644 index 80edb72..0000000 --- a/tests/integrations/_init.js +++ /dev/null @@ -1,21 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -describe('Callbacks', function () { - it('should have a NGROK_URL', function () { - const URL = global.NGROK_URL - expect(URL.length).to.be.greaterThan(5) - }) - it('throws an event and handles it', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.on('hello', function (payload) { - expect(payload).to.be('From CallbacksEmitter') - done() - }) - if (!URL) { throw new Error('Missing URL') } - got(URL).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) -}) diff --git a/tests/integrations/accountbalance.test.js b/tests/integrations/accountbalance.test.js deleted file mode 100644 index 2b8407d..0000000 --- a/tests/integrations/accountbalance.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('Account Callbacks', function () { - /** - * Simulates timeouts coz lol, apparently there is no such way in Daraja - */ - it('simulates a timeout', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.once('accountBalanceTimeout', function (payload) { - expect(payload.simulation).to.be(true) - expect(payload.success).to.be(true) - done() - }) - got.post(URL + '/accountbalance/timeout', { data: 'test' }).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) - it('gets an account balance callback from Daraja', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - const { shortCode } = testInstance.configs - this.retries(3) - testInstance.accountBalance(shortCode, 4, URL + '/accountbalance/timeout', URL + '/accountbalance/success').catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - emitter.once('accountBalanceCallback', function (payload) { - expect(payload['Result']['ResultDesc']).to.match(/The service request is processed successfully/) - done() - }) - }) -}) diff --git a/tests/integrations/b2b.test.js b/tests/integrations/b2b.test.js deleted file mode 100644 index edfa828..0000000 --- a/tests/integrations/b2b.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('B2B Callbacks', function () { - /** - * Simulates timeouts coz lol, apparently there is no such way in Daraja - */ - it('simulates a timeout', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.once('b2bTimeout', function (payload) { - expect(payload.simulation).to.be(true) - expect(payload.success).to.be(true) - done() - }) - got.post(URL + '/b2b/timeout', { data: 'test' }).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) - it('gets an b2b success callback from Daraja', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - const { shortCode } = testInstance.configs - const testShortcode2 = 600000 - testInstance.b2b(shortCode, testShortcode2, 100, URL + '/b2b/timeout', URL + '/b2b/success').catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - emitter.once('b2bSuccessCallback', function (payload) { - expect(payload['Result']['ResultDesc']).to.match(/The service request is processed successfully/) - done() - }) - }) -}) diff --git a/tests/integrations/b2c.test.js b/tests/integrations/b2c.test.js deleted file mode 100644 index e924a1b..0000000 --- a/tests/integrations/b2c.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('B2C Callbacks', function () { - /** - * Simulates timeouts coz lol, apparently there is no such way in Daraja - */ - it('simulates a timeout', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.once('b2cTimeout', function (payload) { - expect(payload.simulation).to.be(true) - expect(payload.success).to.be(true) - done() - }) - got.post(URL + '/b2c/timeout', { data: 'test' }).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) - it('gets an b2c success callback from Daraja', function (done) { - this.timeout(15000) - this.retries(3) - const URL = global.NGROK_URL - const { shortCode } = testInstance.configs - const testMSISDN = 254708374149 - testInstance.b2c(shortCode, testMSISDN, 100, URL + '/b2c/timeout', URL + '/b2c/success').catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - emitter.once('b2cSuccessCallback', function (payload) { - expect(payload['Result']['ResultDesc']).to.match(/The service request is processed successfully/) - done() - }) - }) -}) diff --git a/tests/integrations/c2b.test.js b/tests/integrations/c2b.test.js deleted file mode 100644 index 4084d58..0000000 --- a/tests/integrations/c2b.test.js +++ /dev/null @@ -1,25 +0,0 @@ -const expect = require('expect.js') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('c2b Callbacks', function () { - it('gets an c2b success callback from Daraja', function (done) { - this.timeout(25000) - const URL = global.NGROK_URL - const { shortCode } = testInstance.configs - const testMSISDN = 254708374149 - testInstance.c2bRegister(URL + '/c2b/validation', URL + '/c2b/success') - .then(() => { - testInstance.c2bSimulate(testMSISDN, 100, Math.random().toString(35).substr(2, 7)).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message + ' ' + e.response.message) - }) - }) - .catch(e => { - throw new Error('Something went wrong. Message: ' + e.message + ' ' + e.response.message) - }) - emitter.on('c2bSuccessCallback', function (payload) { - expect(payload['BusinessShortCode']).to.be(`${shortCode}`) - expect(payload['MSISDN']).to.be(`${testMSISDN}`) - done() - }) - }) -}) diff --git a/tests/integrations/lipa-na-mpesa.test.js b/tests/integrations/lipa-na-mpesa.test.js deleted file mode 100644 index 76ba9df..0000000 --- a/tests/integrations/lipa-na-mpesa.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const expect = require('expect.js') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -let checkoutRequestId = null -describe('Lipa Na Mpesa Online Callbacks', function () { - const testMSISDN = 254708374149 - const amount = 100 - it('gets a lipaNaMpesa success callback from Daraja', function (done) { - // Since we have to wait for a time out and das sad and - this.timeout(200 * 1000) // 200s - const URL = global.NGROK_URL - testInstance.lipaNaMpesaOnline(testMSISDN, amount, URL + '/lipanampesa/success', Math.random().toString(35).substr(2, 7)) - .then(({ data }) => { - checkoutRequestId = data['CheckoutRequestID'] - }) - .catch(e => { - throw new Error('Something went wrong. Message: ' + e.message + ' ' + e.response.message) - }) - emitter.on('lipaNaMpesaOnlineSuccessCallback', function (payload) { - expect(payload).to.be.ok() - done() - }) - }) - - it(`allows checking of lipaNaMpesa status for ${checkoutRequestId}`, function (done) { - this.timeout(5000) - testInstance.lipaNaMpesaQuery(checkoutRequestId).then(({ data }) => { - expect(data['ResponseDescription']).to.match(/The service request has been accepted successsfully/) - done() - }).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message + ' ' + e.response.message) - }) - }) -}) diff --git a/tests/integrations/reversal.test.js b/tests/integrations/reversal.test.js deleted file mode 100644 index 547d62b..0000000 --- a/tests/integrations/reversal.test.js +++ /dev/null @@ -1,33 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('Reversal Callbacks', function () { - /** - * Simulates timeouts coz lol, apparently there is no such way in Daraja - */ - it('simulates a timeout', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.once('reversalTimeout', function (payload) { - expect(payload.simulation).to.be(true) - expect(payload.success).to.be(true) - done() - }) - got.post(URL + '/reversal/timeout', { data: 'test' }).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) - it('gets an reversal success callback from Daraja', function (done) { - this.timeout(15000) - this.retries(3) - const URL = global.NGROK_URL - testInstance.reversal('LKXXXX1234', 100, URL + '/reversal/timeout', URL + '/reversal/success').catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - emitter.once('reversalSuccessCallback', function (payload) { - expect(payload['Result']['ResultDesc']).to.match(/The OriginalTransactionID is invalid./) - done() - }) - }) -}) diff --git a/tests/integrations/transactionstatus.test.js b/tests/integrations/transactionstatus.test.js deleted file mode 100644 index 3830287..0000000 --- a/tests/integrations/transactionstatus.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const expect = require('expect.js') -const got = require('got') -const emitter = require('.././helpers/callbacksemitter') -const testInstance = require('.././helpers/instance') -describe('TransactionStatus Callbacks', function () { - /** - * Simulates timeouts coz lol, apparently there is no such way in Daraja - */ - it('simulates a timeout', function (done) { - this.timeout(15000) - const URL = global.NGROK_URL - emitter.once('transactionStatusTimeout', function (payload) { - expect(payload.simulation).to.be(true) - expect(payload.success).to.be(true) - done() - }) - got.post(URL + '/transactionstatus/timeout', { data: 'test' }).then(r => r).catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - }) - it('gets a transactionStatus success callback from Daraja', function (done) { - this.timeout(15000) - this.retries(3) - const URL = global.NGROK_URL - const { shortCode } = testInstance.configs - testInstance.transactionStatus('LKXXXX1234', shortCode, 4, URL + '/transactionstatus/timeout', URL + '/transactionstatus/success').catch(e => { - throw new Error('Something went wrong. Message: ' + e.message) - }) - emitter.once('transactionStatusSuccessCallback', function (payload) { - expect(payload['Result']['ResultDesc']).to.match(/The format of parameter null is invalid./) - done() - }) - }) -}) diff --git a/tests/unit/index.test.js b/tests/unit/index.test.js deleted file mode 100644 index 36d7e08..0000000 --- a/tests/unit/index.test.js +++ /dev/null @@ -1,54 +0,0 @@ -const expect = require('expect.js') -const Mpesa = require('../.././src/m-pesa') -const instance = new Mpesa({ consumerKey: 'test', consumerSecret: 'test' }) -const { - accountBalance, - b2b, - b2c, - c2bRegister, - c2bSimulate, - lipaNaMpesaOnline, - lipaNaMpesaQuery, - oAuth, - reversal, - transactionStatus -} = instance - -describe('All Methods are Callble', function () { - [ - accountBalance, - b2b, - b2c, - c2bRegister, - c2bSimulate, - lipaNaMpesaOnline, - lipaNaMpesaQuery, - oAuth, - reversal, - transactionStatus ].map(f => { - it(f.name, function () { - expect(typeof f).to.be('function') - }) - }) -}) - -describe('C2B', function () { - const productionInstance = new Mpesa({ - consumerKey: 'test', - consumerSecret: 'test', - environment: 'production' - }) - - it('should throw error in production', function () { - let threwError = false - - try { - productionInstance.c2bSimulate() - } catch (e) { - threwError = true - expect(e.message).to.be('Cannot call C2B simulate in production.') - } finally { - expect(threwError).to.be(true) - } - }) -}) diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index b5d8003..0000000 --- a/yarn.lock +++ /dev/null @@ -1,4066 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.51.tgz#bd71d9b192af978df915829d39d4094456439a0c" - integrity sha1-vXHZsZKvl435FYKdOdQJRFZDmgw= - dependencies: - "@babel/highlight" "7.0.0-beta.51" - -"@babel/generator@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.51.tgz#6c7575ffde761d07485e04baedc0392c6d9e30f6" - integrity sha1-bHV1/952HQdIXgS67cA5LG2eMPY= - dependencies: - "@babel/types" "7.0.0-beta.51" - jsesc "^2.5.1" - lodash "^4.17.5" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/helper-function-name@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.51.tgz#21b4874a227cf99ecafcc30a90302da5a2640561" - integrity sha1-IbSHSiJ8+Z7K/MMKkDAtpaJkBWE= - dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.51" - "@babel/template" "7.0.0-beta.51" - "@babel/types" "7.0.0-beta.51" - -"@babel/helper-get-function-arity@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.51.tgz#3281b2d045af95c172ce91b20825d85ea4676411" - integrity sha1-MoGy0EWvlcFyzpGyCCXYXqRnZBE= - dependencies: - "@babel/types" "7.0.0-beta.51" - -"@babel/helper-split-export-declaration@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.51.tgz#8a6c3f66c4d265352fc077484f9f6e80a51ab978" - integrity sha1-imw/ZsTSZTUvwHdIT59ugKUauXg= - dependencies: - "@babel/types" "7.0.0-beta.51" - -"@babel/highlight@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.51.tgz#e8844ae25a1595ccfd42b89623b4376ca06d225d" - integrity sha1-6IRK4loVlcz9QriWI7Q3bKBtIl0= - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -"@babel/parser@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.51.tgz#27cec2df409df60af58270ed8f6aa55409ea86f6" - integrity sha1-J87C30Cd9gr1gnDtj2qlVAnqhvY= - -"@babel/parser@^7.4.4": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872" - integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew== - -"@babel/template@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.51.tgz#9602a40aebcf357ae9677e2532ef5fc810f5fbff" - integrity sha1-lgKkCuvPNXrpZ34lMu9fyBD1+/8= - dependencies: - "@babel/code-frame" "7.0.0-beta.51" - "@babel/parser" "7.0.0-beta.51" - "@babel/types" "7.0.0-beta.51" - lodash "^4.17.5" - -"@babel/traverse@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.51.tgz#981daf2cec347a6231d3aa1d9e1803b03aaaa4a8" - integrity sha1-mB2vLOw0emIx06odnhgDsDqqpKg= - dependencies: - "@babel/code-frame" "7.0.0-beta.51" - "@babel/generator" "7.0.0-beta.51" - "@babel/helper-function-name" "7.0.0-beta.51" - "@babel/helper-split-export-declaration" "7.0.0-beta.51" - "@babel/parser" "7.0.0-beta.51" - "@babel/types" "7.0.0-beta.51" - debug "^3.1.0" - globals "^11.1.0" - invariant "^2.2.0" - lodash "^4.17.5" - -"@babel/types@7.0.0-beta.51": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.51.tgz#d802b7b543b5836c778aa691797abf00f3d97ea9" - integrity sha1-2AK3tUO1g2x3iqaReXq/APPZfqk= - dependencies: - esutils "^2.0.2" - lodash "^4.17.5" - to-fast-properties "^2.0.0" - -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - -"@types/node@^8.10.30": - version "8.10.49" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.49.tgz#f331afc5efed0796798e5591d6e0ece636969b7b" - integrity sha512-YX30JVx0PvSmJ3Eqr74fYLGeBxD+C7vIL20ek+GGGLJeUbVYRUW3EzyAXpIRA0K8c8o0UWqR/GwEFYiFoz1T8w== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - -acorn@^5.5.0: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== - -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= - -ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ajv@^6.5.5: - version "6.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" - integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -append-transform@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" - integrity sha1-126/jKlNJ24keja61EpLdKthGZE= - dependencies: - default-require-extensions "^1.0.0" - -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-includes@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" - integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - -axios@^0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" - integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== - dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" - -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -binary@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" - integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= - dependencies: - buffers "~0.1.1" - chainsaw "~0.1.0" - -bluebird@^3.5.4: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== - -body-parser@1.19.0, body-parser@^1.18.2: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffers@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.1" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - -caching-transform@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-1.0.1.tgz#6dbdb2f20f8d8fbce79f3e94e9d1742dcdf5c0a1" - integrity sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE= - dependencies: - md5-hex "^1.2.0" - mkdirp "^0.5.1" - write-file-atomic "^1.1.4" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -catharsis@^0.8.10: - version "0.8.10" - resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.10.tgz#364198c1fbf084ae17028ee33ec7db53ca942ee6" - integrity sha512-l2OUaz/3PU3MZylspVFJvwHCVfWyvcduPq4lv3AzZ2pJzZCo7kNKFNyatwujD7XgvGkNAE/Jhhbh2uARNwNkfw== - dependencies: - lodash "^4.17.11" - -chainsaw@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" - integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= - dependencies: - traverse ">=0.3.0 <0.4" - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -clone-response@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== - -commander@~2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.0, component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -convert-source-map@^1.5.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== - dependencies: - safe-buffer "~5.1.1" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -cookiejar@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cross-spawn@^4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" - integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -debug-log@^1.0.0, debug-log@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" - integrity sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8= - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@3.1.0, debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -decompress-zip@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/decompress-zip/-/decompress-zip-0.3.2.tgz#f3fa2841666abce394604f4a9e8a7085c202d464" - integrity sha512-Ab1QY4LrWMrUuo53lLnmGOby7v8ryqxJ+bKibKSiPisx+25mhut1dScVBXAYx14i/PqSrFZvR2FRRazhLbvL+g== - dependencies: - binary "^0.3.0" - graceful-fs "^4.1.3" - mkpath "^0.1.0" - nopt "^3.0.1" - q "^1.1.2" - readable-stream "^1.1.8" - touch "0.0.3" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -default-require-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" - integrity sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= - dependencies: - strip-bom "^2.0.0" - -define-properties@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -deglob@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.1.tgz#d268e168727799862e8eac07042e165957c1f3be" - integrity sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw== - dependencies: - find-root "^1.0.0" - glob "^7.0.5" - ignore "^3.0.9" - pkg-config "^1.1.0" - run-parallel "^1.1.2" - uniq "^1.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.0.2, doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -dotenv@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" - integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -entities@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.7.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" - integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-keys "^1.0.12" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -eslint-config-standard-jsx@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz#4abfac554f38668e0078c664569e7b2384e5d2aa" - integrity sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg== - -eslint-config-standard@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz#87ee0d3c9d95382dc761958cbb23da9eea31e0ba" - integrity sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw== - -eslint-import-resolver-node@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" - integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== - dependencies: - debug "^2.6.9" - resolve "^1.5.0" - -eslint-module-utils@^2.1.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" - integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== - dependencies: - debug "^2.6.8" - pkg-dir "^2.0.0" - -eslint-plugin-import@~2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" - integrity sha1-JgAu+/ylmJtyiKwEdQi9JPIXsWk= - dependencies: - builtin-modules "^1.1.1" - contains-path "^0.1.0" - debug "^2.6.8" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.1.1" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" - read-pkg-up "^2.0.0" - -eslint-plugin-node@~6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" - integrity sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw== - dependencies: - ignore "^3.3.6" - minimatch "^3.0.4" - resolve "^1.3.3" - semver "^5.4.1" - -eslint-plugin-promise@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz#f4bde5c2c77cdd69557a8f69a24d1ad3cfc9e67e" - integrity sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg== - -eslint-plugin-react@~7.7.0: - version "7.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" - integrity sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA== - dependencies: - doctrine "^2.0.2" - has "^1.0.1" - jsx-ast-utils "^2.0.1" - prop-types "^15.6.0" - -eslint-plugin-standard@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" - integrity sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI= - -eslint-scope@^3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== - -eslint@~4.18.0: - version "4.18.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" - integrity sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw== - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.2" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" - -espree@^3.5.2: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== - dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - -expect.js@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/expect.js/-/expect.js-0.3.1.tgz#b0a59a0d2eff5437544ebf0ceaa6015841d09b5b" - integrity sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s= - -express@^4.16.3: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" - integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= - dependencies: - commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" - -find-root@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -flat-cache@^1.2.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" - integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== - dependencies: - circular-json "^0.3.1" - graceful-fs "^4.1.2" - rimraf "~2.6.2" - write "^0.2.1" - -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - -foreground-child@^1.5.3, foreground-child@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" - integrity sha1-T9ca0t/elnibmApcCilZN8svXOk= - dependencies: - cross-spawn "^4" - signal-exit "^3.0.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@^2.3.1, form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -formidable@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" - integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - -glob@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== - dependencies: - 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@^7.0.5, glob@^7.0.6, glob@^7.1.2, glob@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - dependencies: - 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" - -globals@^11.0.1, globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -got@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.9: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -handlebars@^4.0.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" - integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== - dependencies: - neo-async "^2.6.0" - optimist "^0.6.1" - source-map "^0.6.1" - optionalDependencies: - uglify-js "^3.1.4" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= - -hosted-git-info@^2.1.4: - version "2.7.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== - -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - -http-errors@1.7.2, http-errors@~1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -iconv-lite@0.4.24, iconv-lite@^0.4.17: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^3.0.9, ignore@^3.3.3, ignore@^3.3.6: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - -invariant@^2.2.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-buffer@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= - -is-plain-obj@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-retry-allowed@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== - dependencies: - has-symbols "^1.0.0" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" - integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== - -istanbul-lib-coverage@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== - -istanbul-lib-hook@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" - integrity sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== - dependencies: - append-transform "^0.4.0" - -istanbul-lib-instrument@^2.1.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-2.3.2.tgz#b287cbae2b5f65f3567b05e2e29b275eaf92d25e" - integrity sha512-l7TD/VnBsIB2OJvSyxaLW/ab1+92dxZNH9wLH7uHPPioy3JZ8tnx2UXUdKmdkgmP2EFPzg64CToUP6dAS3U32Q== - dependencies: - "@babel/generator" "7.0.0-beta.51" - "@babel/parser" "7.0.0-beta.51" - "@babel/template" "7.0.0-beta.51" - "@babel/traverse" "7.0.0-beta.51" - "@babel/types" "7.0.0-beta.51" - istanbul-lib-coverage "^2.0.1" - semver "^5.5.0" - -istanbul-lib-report@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" - integrity sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== - dependencies: - istanbul-lib-coverage "^1.2.1" - mkdirp "^0.5.1" - path-parse "^1.0.5" - supports-color "^3.1.2" - -istanbul-lib-source-maps@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" - integrity sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== - dependencies: - debug "^3.1.0" - istanbul-lib-coverage "^1.2.1" - mkdirp "^0.5.1" - rimraf "^2.6.1" - source-map "^0.5.3" - -istanbul-reports@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" - integrity sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== - dependencies: - handlebars "^4.0.3" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.9.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js2xmlparser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.0.tgz#ae14cc711b2892083eed6e219fbc993d858bc3a5" - integrity sha512-WuNgdZOXVmBk5kUPMcTcVUpbGRzLfNkv7+7APq7WiDihpXVKrgxo6wwRpRl9OQeEBgKCVk9mR7RbzrnNWC8oBw== - dependencies: - xmlcreate "^2.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdoc@^3.5.5: - version "3.6.2" - resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.2.tgz#ee289fc6ba9263b7e4eceb99921179fe1c31489a" - integrity sha512-S2vzg99C5+gb7FWlrK4TVdyzVPGGkdvpDkCEJH1JABi2PKzPeLu5/zZffcJUifgWUJqXWl41Hoc+MmuM2GukIg== - dependencies: - "@babel/parser" "^7.4.4" - bluebird "^3.5.4" - catharsis "^0.8.10" - escape-string-regexp "^2.0.0" - js2xmlparser "^4.0.0" - klaw "^3.0.0" - markdown-it "^8.4.2" - markdown-it-anchor "^5.0.2" - marked "^0.6.2" - mkdirp "^0.5.1" - requizzle "^0.2.2" - strip-json-comments "^3.0.1" - taffydb "2.6.2" - underscore "~1.9.1" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -jsx-ast-utils@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz#0ee4e2c971fb9601c67b5641b71be80faecf0b36" - integrity sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA== - dependencies: - array-includes "^3.0.3" - -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -klaw@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" - integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== - dependencies: - graceful-fs "^4.1.9" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -linkify-it@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db" - integrity sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg== - dependencies: - uc.micro "^1.0.1" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -loose-envify@^1.0.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-it-anchor@^5.0.2: - version "5.2.3" - resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.2.3.tgz#76d07b5cfcf41a14cb6495522ed0f734ced337d9" - integrity sha512-KjEKPZNYoanmTECbh9x1bBsXGJ6dNUTxIFg5YhdBxYkx/+27LNVUzh7Ctlb7jxadgGCWMX9tt46Aaby7Af8xSg== - -markdown-it@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" - integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== - dependencies: - argparse "^1.0.7" - entities "~1.1.1" - linkify-it "^2.0.0" - mdurl "^1.0.1" - uc.micro "^1.0.5" - -marked@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.2.tgz#c574be8b545a8b48641456ca1dbe0e37b6dccc1a" - integrity sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA== - -math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - -md5-hex@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" - integrity sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ= - dependencies: - md5-o-matic "^0.1.1" - -md5-o-matic@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" - integrity sha1-givM1l4RfFFPqxdrJZRdVBAKA8M= - -mdurl@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -mem@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== - dependencies: - source-map "^0.6.1" - -methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== - dependencies: - mime-db "1.40.0" - -mime@1.6.0, mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-response@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -mkpath@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-0.1.0.tgz#7554a6f8d871834cc97b5462b122c4c124d6de91" - integrity sha1-dVSm+Nhxg0zJe1RisSLEwSTW3pE= - -mocha@^5.0.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== - dependencies: - browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" - diff "3.5.0" - escape-string-regexp "1.0.5" - glob "7.1.2" - growl "1.10.5" - he "1.1.1" - minimatch "3.0.4" - mkdirp "0.5.1" - supports-color "5.4.0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1, ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -neo-async@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - -ngrok@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/ngrok/-/ngrok-3.1.1.tgz#d4d70e455fff94b56755c2007c41e4daa5e77fa9" - integrity sha512-dCW/Ni12GRBL7XIyiFmilKOfCW7UVFf65I/HpE8FC5rXGJwdhIYLc9Qr05GRb6hNs6fZGwyLpcDLnDhUSgZasQ== - dependencies: - "@types/node" "^8.10.30" - decompress-zip "^0.3.2" - request "^2.88.0" - request-promise-native "^1.0.5" - uuid "^3.3.2" - -nopt@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= - dependencies: - abbrev "1" - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -nyc@^12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-12.0.2.tgz#8a4a4ed690966c11ec587ff87eea0c12c974ba99" - integrity sha1-ikpO1pCWbBHsWH/4fuoMEsl0upk= - dependencies: - archy "^1.0.0" - arrify "^1.0.1" - caching-transform "^1.0.0" - convert-source-map "^1.5.1" - debug-log "^1.0.1" - default-require-extensions "^1.0.0" - find-cache-dir "^0.1.1" - find-up "^2.1.0" - foreground-child "^1.5.3" - glob "^7.0.6" - istanbul-lib-coverage "^1.2.0" - istanbul-lib-hook "^1.1.0" - istanbul-lib-instrument "^2.1.0" - istanbul-lib-report "^1.1.3" - istanbul-lib-source-maps "^1.2.5" - istanbul-reports "^1.4.1" - md5-hex "^1.2.0" - merge-source-map "^1.1.0" - micromatch "^3.1.10" - mkdirp "^0.5.0" - resolve-from "^2.0.0" - rimraf "^2.6.2" - signal-exit "^3.0.1" - spawn-wrap "^1.4.2" - test-exclude "^4.2.0" - yargs "11.1.0" - yargs-parser "^8.0.0" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-keys@^1.0.12: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -optimist@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^4.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.5, path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-conf@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" - integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg= - dependencies: - find-up "^2.0.0" - load-json-file "^4.0.0" - -pkg-config@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" - integrity sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q= - dependencies: - debug-log "^1.0.0" - find-root "^1.0.0" - xtend "^4.0.1" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= - dependencies: - find-up "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prop-types@^15.6.0: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.0" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.24, psl@^1.1.28: - version "1.1.32" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db" - integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g== - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.7.0, qs@^6.5.1: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-is@^16.8.1: - version "16.8.6" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" - integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - -readable-stream@^1.1.8: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.2.2, readable-stream@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.5.2, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request-promise-core@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346" - integrity sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag== - dependencies: - lodash "^4.17.11" - -request-promise-native@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.7.tgz#a49868a624bdea5069f1251d0a836e0d89aa2c59" - integrity sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w== - dependencies: - request-promise-core "1.1.2" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.2.tgz#df991c0cffbbbdde721504c1455f68f53f7c7bd1" - integrity sha512-oJ6y7JcUJkblRGhMByGNcszeLgU0qDxNKFCiUZR1XyzHyVsev+Mxb1tyygxLd1ORsKee1SA5BInFdUwY64GE/A== - dependencies: - lodash "^4.17.11" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - -resolve-from@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" - integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.10.0, resolve@^1.3.3, resolve@^1.5.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232" - integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw== - dependencies: - path-parse "^1.0.6" - -responselike@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - -run-parallel@^1.1.2: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== - dependencies: - is-fullwidth-code-point "^2.0.0" - -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spawn-wrap@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c" - integrity sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg== - dependencies: - foreground-child "^1.5.6" - mkdirp "^0.5.0" - os-homedir "^1.0.1" - rimraf "^2.6.2" - signal-exit "^3.0.2" - which "^1.3.0" - -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" - integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -standard-engine@~8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-8.0.1.tgz#0b77be8d7ab963675717dbeac1ef1d6675fb62f0" - integrity sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw== - dependencies: - deglob "^2.1.0" - get-stdin "^6.0.0" - minimist "^1.1.0" - pkg-conf "^2.0.0" - -standard@^11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/standard/-/standard-11.0.1.tgz#49be40c76f1d564964b22bbf7309929ad0335e29" - integrity sha512-nu0jAcHiSc8H+gJCXeiziMVZNDYi8MuqrYJKxTgjP4xKXZMKm311boqQIzDrYI/ktosltxt2CbDjYQs9ANC8IA== - dependencies: - eslint "~4.18.0" - eslint-config-standard "11.0.0" - eslint-config-standard-jsx "5.0.0" - eslint-plugin-import "~2.9.0" - eslint-plugin-node "~6.0.0" - eslint-plugin-promise "~3.7.0" - eslint-plugin-react "~7.7.0" - eslint-plugin-standard "~3.0.1" - standard-engine "~8.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-json-comments@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== - dependencies: - component-emitter "^1.2.0" - cookiejar "^2.1.0" - debug "^3.1.0" - extend "^3.0.0" - form-data "^2.3.1" - formidable "^1.2.0" - methods "^1.1.1" - mime "^1.4.1" - qs "^6.5.1" - readable-stream "^2.3.5" - -supertest@^3.0.0: - version "3.4.2" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-3.4.2.tgz#bad7de2e43d60d27c8caeb8ab34a67c8a5f71aad" - integrity sha512-WZWbwceHUo2P36RoEIdXvmqfs47idNNZjCuJOqDz6rvtkk8ym56aU5oglORCpPeXGxT7l9rkJ41+O1lffQXYSA== - dependencies: - methods "^1.1.2" - superagent "^3.8.3" - -supports-color@5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== - dependencies: - has-flag "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^3.1.2: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - -taffydb@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" - integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= - -test-exclude@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" - integrity sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA== - dependencies: - arrify "^1.0.1" - micromatch "^2.3.11" - object-assign "^4.1.0" - read-pkg-up "^1.0.1" - require-main-filename "^1.0.1" - -text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -touch@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/touch/-/touch-0.0.3.tgz#51aef3d449571d4f287a5d87c9c8b49181a0db1d" - integrity sha1-Ua7z1ElXHU8oel2Hyci0kYGg2x0= - dependencies: - nopt "~1.0.10" - -tough-cookie@^2.3.3: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -uc.micro@^1.0.1, uc.micro@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" - integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== - -uglify-js@^3.1.4: - version "3.7.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a" - integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg== - dependencies: - commander "~2.20.3" - source-map "~0.6.1" - -underscore@~1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== - -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9, which@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^1.1.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= - dependencies: - mkdirp "^0.5.1" - -xmlcreate@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.1.tgz#2ec38bd7b708d213fd1a90e2431c4af9c09f6a52" - integrity sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA== - -xtend@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yargs-parser@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== - dependencies: - camelcase "^4.1.0" - -yargs-parser@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" - integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= - dependencies: - camelcase "^4.1.0" - -yargs@11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" - integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^9.0.2"