[
  {
    "path": ".circleci/config.yml",
    "content": "# Javascript Node CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-javascript/ for more details\n#\nversion: 2\njobs:\n  build_test:\n    docker:\n      - image: circleci/node:9.11.1\n    working_directory: ~/repo\n    steps:\n      - checkout\n      - run: npm install\n      - run: npm run test\n\nworkflows:\n  version: 2\n  test:\n    jobs:\n      - build_test\n"
  },
  {
    "path": ".dockerignore",
    "content": "node_modules\ndocs\nfeatures\n.npmrc\n.nvmrc\n"
  },
  {
    "path": ".gitignore",
    "content": "/dist\n/logs\n/npm-debug.log\n/node_modules\n.DS_Store\n.idea/\n.env\n.vscode\nnode_modules\ndist\npackage-lock.json\n.nyc_output\n/**/package-lock.json\n/**/node_modules\n/**/dist\npackage-lock.json\nlerna-debug.log\n*.swp\n"
  },
  {
    "path": ".gitlab-ci.yml",
    "content": "image: node:8.9.0\n\nstages:\n  - build\n  - lint\n  - test\n\nbefore_script:\n  - npm install\n  - apt-get update\n  - apt-get install -y netcat\n\n\n# This folder is cached between builds\n# http://docs.gitlab.com/ce/ci/yaml/README.html#cache\ncache:\n  paths:\n  - node_modules/\n\ntest:\n  script:\n   - npm run build\n   - npm run test\n\nlint:\n  script:\n   - npm run lint\n\nbuild:\n  script:\n   - npm run build\n"
  },
  {
    "path": ".npmrc",
    "content": "save-exact=true\npackage-lock=false\n"
  },
  {
    "path": ".nvmrc",
    "content": "9\n"
  },
  {
    "path": ".prettierignore",
    "content": "/.history\n/node_modules\n/.vscode\n/.idea\n/dist\n*/**/*.temp\n*/**/*.temp.*\n*/**/package.json\n*/**/package-lock.json\npackage.json\npackage-lock.json"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"trailingComma\": \"all\",\n  \"singleQuote\": true,\n  \"arrowParens\" :\"always\"\n}"
  },
  {
    "path": ".rebuild.ts",
    "content": ""
  },
  {
    "path": "Dockerfile",
    "content": "FROM keymetrics/pm2:8-alpine\n\nCOPY .env /.env\nCOPY entrypoint.sh /\nCOPY package.json /usr/src/app/package.json\n\nWORKDIR /tmp/app\n\nRUN apk --no-cache add git openssh-client curl\n\nCOPY . /tmp/app\n\nRUN export $(cat /.env | xargs) && NODE_ENV=development npm install --progress=false\nRUN export $(cat /.env | xargs)  && /tmp/app/node_modules/.bin/tsc --project /tmp/app --outDir /usr/src/app/\nRUN export $(cat /.env | xargs) && npm install --progress=false --prefix /usr/src/app/\n\nWORKDIR /usr/src/app\n\nCMD [\"npm\", \"run\", \"start:production\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://hadron.pro/\" target=\"blank\">\n  <img src=\"./logo3.png\" alt=\"Hadron Logo\" /></a>\n</p>\n\n[![CircleCI](https://circleci.com/gh/brainhubeu/hadron.svg?style=svg)](https://circleci.com/gh/brainhubeu/hadron)\n\n## Why?\n\n**Hadron's purpose is to facilitate the building of Node.js applications:**\n\n### Low-level framework-agnostic\n\nYour application is built independently from other frameworks (Express, Koa). Hadron creates a layer between HTTP requests and your app written in plain Javascript.\n\nHadron abstracts away underlying request and response objects, providing simple data structures as input/output of your routes' handlers, making them simple to test and easy to deal with.\n\n### Dependency injection\n\nThe dependency injection pattern enables you to easily change interface implementation. Hadron gives us the power to create SOLID applications.\n\nContainers as a dependency management solution provides a convenient way to access all dependencies in functions.\n\n### Modular structure\n\nThe modular structure enables you to add/remove packages or create your own extensions. Hadron provides a complete solution for request processing using separate packages.\n\nCurrent packages:\n\n* security management\n* input validation\n* database integration (through TypeORM)\n* data serialization\n* logging\n* events handling\n* CLI tool\n\nBuilt with TypeScript, but it's primary target is JavaScript apps. Hadron’s API embraces current ECMAScript standards, with the cherry of good IDE support via codebase types declarations on top.\n\n> To read more about hadron check out our article: [How to use Hadron?](https://brainhub.eu/blog/building-api-expressjs-and-hadron/)\n\n## Installation\n\n* Install Node.js. We recommend using the latest version, installation details on [nodejs.org](https://nodejs.org)\n\n* Install following modules from npm:\n\n```bash\nnpm install @brainhubeu/hadron-core @brainhubeu/hadron-express express --save\n```\n\n## Hello World app\n\nLet's start with a simple Hello World app. It will give you a quick grasp of the framework.\n\n```javascript\nconst hadron = require('@brainhubeu/hadron-core').default;\nconst express = require('express');\n\nconst port = 8080;\nconst expressApp = express();\n\nconst config = {\n  routes: {\n    helloWorldRoute: {\n      path: '/',\n      callback: () => 'Hello world!',\n      methods: ['get'],\n    },\n  },\n};\n\nhadron(expressApp, [require('@brainhubeu/hadron-express')], config).then(() => {\n  expressApp.listen(port, () =>\n    console.log(`Listening on http://localhost:${port}`),\n  );\n});\n```\n\n## Documentation\n\nHadron documentation can be found at [http://hadron.pro](http://hadron.pro)\n\n## Getting Started\n\n#### Requirements\n\n* Installed GIT\n* Installed node.js (we recommend using [nvm](https://github.com/creationix/nvm) to run multiple versions of node).\n\nWe recommend using latest version of node. If you want to use older versions you may need to add [babel-polyfill](https://babeljs.io/docs/usage/polyfill/) to use [some features](http://node.green/).\n\n#### Clone it\n\n```sh\ngit clone git@github.com:brainhubeu/hadron.git\ncd brainhub-framework-app\n```\n\n#### Install dependencies\n\n```sh\nnpm install\n```\n\n#### Run development server\n\n```sh\nnpm run dev\n```\n\n#### Run production server\n\n```sh\nnpm start\n```\n\n## Running tests\n\n#### All tests\n\n```sh\nnpm run test\n# or\nPORT=8181 npm run test\n```\n\n#### Unit tests\n\nRun unit tests for each package:\n```sh\nnpm run test:unit\n```\n\nRun unit tests for a single package:\n```sh\nnpm run test:package <package name>\n```\n\n#### E2E tests\n\n```sh\nPORT=8181 npm run test:e2e\n```\n\nIt will run `test.sh` script which in turn, will run app, wait for it to start listening and run `npm run test:cucumber` command.\nYou need to provide the script with valid PORT or default (8080) will be used.\n\n#### Linter\n\n```sh\nnpm run lint        # to just show linter errors and warnings\nnpm run lint:fix    # to fix the errors and show what's left\n```\n\n### Typescript types management\n\n**Note!** Because we're using `\"noImplicitAny\": true`, we are required to have a `.d.ts` file for **every** library we use. While we could set `noImplicitAny` to `false` to silence errors about missing `.d.ts` files, it is a best practice to have a `.d.ts` file for every library.\n\n1.  After installing any npm package as a dependency or dev dependency, immediately try to install the `.d.ts` file via `@types`. If it succeeds, you are done. If not, continue to next step.\n2.  Try to generate a `.d.ts` file with dts-gen. If it succeeds, you are done. If not, continue to next step.\n3.  Create a file called `<some-library>.d.ts` in `types` folder.\n4.  Add the following code:\n\n```ts\ndeclare module '<some-library>';\n```\n\n5.  At this point everything should compile with no errors and you can either improve the types in the `.d.ts` file by following this [guide on authoring `.d.ts` files](http://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) or continue with no types.\n\n## Lerna\n\n1.  To run `npm i` on all packages, and compile them, just run\n\n```bash\n  lerna bootstrap\n```\n\n2.  To run any command on all packages, just can use `exec` command.\n    F.e. to compile all packages, you can run\n\n```bash\n  lerna exec tsc\n```\n\n3.  To clean all `node_modules` in packages, run\n\n```bash\n  lerna clean\n```\n\n4.  To clean all `node_modules` AND `dist` directories, run\n\n```bash\n  npm run clean\n```\n\n5.  To add dependency between packages, run\n\n```bash\n  lerna add <source-package-name> --scope=<target-package-name1>, <target-package-name2>\n```\n\n6.  To publish to npm, run\n\n```bash\n  lerna publish\n```\n\nTo get more command, please visit this [link](https://github.com/lerna/lerna).\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '2'\n\nnetworks:\n  brainhub: ~\n\nservices:\n  brainhub-framework-app:\n    image: brainhub-framework-app\n    build:\n      context: .\n    container_name: fs-brainhub-framework-app\n    volumes:\n      - ./:/usr/src/app\n    ports:\n      - 8080:8080\n    environment:\n      NODE_ENV: development\n    command: npm run start:development\n    networks:\n      brainhub: ~\n"
  },
  {
    "path": "entrypoint.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nif [ ! -f /usr/src/app/node_modules/.lock ] && [ -f /usr/src/app/package.json ]; then\n    npm install --progress=false\n    touch /usr/src/app/node_modules/.lock\nfi\n\nexec \"$@\"\n"
  },
  {
    "path": "features/step_definitions/steps.ts",
    "content": "import { defineSupportCode } from 'cucumber';\nimport stepsSupport from '@brainhubeu/cucumber-steps';\n\ndefineSupportCode(stepsSupport);\n"
  },
  {
    "path": "features/step_definitions/theBestSteps.ts",
    "content": "import { defineSupportCode } from 'cucumber';\n\n/* tslint:disable:only-arrow-functions ter-prefer-arrow-callback */\n\ndefineSupportCode(function({ Given, When, Then }) {\n  Given('brainhub is the best', function(callback) {\n    callback();\n  });\n\n  When('add {string} to {string}', function(number1, number2) {\n    this.result = parseInt(number1, 10) + parseInt(number2, 10);\n  });\n\n  Then('the result is {string}', function(result) {\n    if (this.result !== parseInt(result, 10)) {\n      throw new Error(\n        `Expected result to be equal ${result} but it is ${this.result}`,\n      );\n    }\n  });\n\n  Then('the result is null', function() {\n    if (this.result !== null) {\n      throw new Error(`Expected result to be null but it is ${this.result}`);\n    }\n  });\n});\n"
  },
  {
    "path": "features/support/hooks/mock.ts",
    "content": "import { defineSupportCode } from 'cucumber';\nimport * as superagent from 'superagent';\nimport Client from '../scripts/Client';\n\ndefineSupportCode(({ Before }) => {\n  Before(function(scenarioResult) {\n    this.client = new Client(superagent);\n    this.client.setHost('http://localhost:8080');\n  });\n});\n"
  },
  {
    "path": "features/support/scripts/Client.ts",
    "content": "import Response from './Response';\n\nconst METHOD = {\n  DELETE: 'del',\n  GET: 'get',\n  PATCH: 'patch',\n  POST: 'post',\n  PUT: 'put',\n};\n\nexport default class Client {\n  public superagent: any;\n  public host: string;\n  public headers: object;\n  constructor(superagent) {\n    this.superagent = superagent;\n    this.headers = {};\n\n    Object.keys(METHOD).forEach((methodKey) => {\n      const method = METHOD[methodKey.toUpperCase()];\n      this[methodKey.toLowerCase()] = (path, body) => {\n        return this.createRequest(method, path, body);\n      };\n    });\n  }\n\n  public setHost(host) {\n    this.host = host;\n  }\n\n  public createRequest(method, path, body) {\n    const request = this.superagent[method.toLowerCase()](this.host + path);\n\n    this.addRequestHeaders(request);\n\n    const createdRequest =\n      method.toLowerCase() !== 'get' ? request.send(body) : request;\n\n    //\n    return createdRequest.then(\n      // tslint:disable:no-shadowed-variable\n      ({ body, status }) => new Response(body, status),\n      ({ response: { body, status } }) => new Response(body, status),\n    );\n  }\n\n  public addRequestHeaders(request) {\n    Object.keys(this.headers).map((name) => {\n      request.set(name, this.headers[name]);\n    });\n  }\n\n  public setHeader(name, value) {\n    this.headers[name] = value;\n  }\n}\n"
  },
  {
    "path": "features/support/scripts/Response.ts",
    "content": "export default class Response {\n  public status: any;\n  public body: any;\n  constructor(body, status) {\n    this.body = body;\n    this.status = status;\n  }\n}\n"
  },
  {
    "path": "features/support/world.ts",
    "content": "import { defineSupportCode } from 'cucumber';\n\n/* tslint:disable:only-arrow-functions ter-prefer-arrow-callback */\n\ndefineSupportCode(function({ setWorldConstructor }) {\n  const customWorld = function() {\n    this.result = null;\n  };\n\n  setWorldConstructor(customWorld);\n});\n"
  },
  {
    "path": "features/theBest.feature",
    "content": "Feature: The Best\n\n  As a Brainhub\n  We want to become best in the world\n\n  Scenario: Adding two numbers\n    Given brainhub is the best\n    When add \"2\" to \"3\"\n    Then the result is \"5\"\n\n  Scenario: Not adding two numbers\n    Then the result is null\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"lerna\": \"2.9.0\",\n  \"packages\": [\n    \"packages/hadron-logger\",\n    \"packages/hadron-utils\",\n    \"packages/hadron-error-handler\",\n    \"packages/hadron-core\",\n    \"packages/hadron-file-locator\",\n    \"packages/hadron-json-provider\",\n    \"packages/hadron-serialization\",\n    \"packages/hadron-validation\",\n    \"packages/hadron-typeorm\",\n    \"packages/hadron-events\",\n    \"packages/hadron-express\",\n    \"packages/hadron-oauth\",\n    \"packages/hadron-auth\",\n    \"packages/hadron-demo\"\n  ],\n  \"version\": \"independent\"\n}\n"
  },
  {
    "path": "ormconfig.json",
    "content": "[\n    {\n        \"name\": \"postgres\",\n        \"type\": \"postgres\",\n        \"host\": \"localhost\",\n        \"port\": 5432,\n        \"username\": \"postgres\",\n        \"password\":\"mysecretpassword\",\n        \"database\": \"_test\",\n        \"synchronize\": true,\n        \"logging\": false,\n        \"autoSchemaSync\": true,\n        \"entities\": [\n            \"../../src/entity/**/*.ts\"\n        ],\n        \"migrations\": [\n            \"../../src/migration/**/*.ts\"\n        ],\n        \"subscribers\": [\n            \"../../src/subscriber/**/*.ts\"\n        ]\n    },\n    {\n        \"name\": \"mysql\",\n        \"type\": \"mysql\",\n        \"host\": \"localhost\",\n        \"port\": 3306,\n        \"username\": \"root\",\n        \"password\":\"my-secret-pw\",\n        \"database\": \"_test\",\n        \"synchronize\": true,\n        \"logging\": false,\n        \"autoSchemaSync\": true,\n        \"entities\": [\n            \"../../src/entity/**/*.ts\"\n        ],\n        \"migrations\": [\n            \"../../src/migration/**/*.ts\"\n        ],\n        \"subscribers\": [\n            \"../../src/subscriber/**/*.ts\"\n        ]\n    }\n]\n"
  },
  {
    "path": "package-test.sh",
    "content": "#!/usr/bin/env sh\n\n# this runs unit tests on an individual package\n# Usage example: ./package-test.sh oauth\n./node_modules/mocha/bin/mocha -r ts-node/register packages/hadron-$1/src/__tests__/*\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"brainhub-framework-app\",\n  \"version\": \"1.0.0-alpha.1\",\n  \"description\": \"Brainhub framework app\",\n  \"main\": \"dist\",\n  \"scripts\": {\n    \"start\": \"NODE_ENV=production NODE_PATH=./packages/hadron-demo/dist npm start --prefix packages/hadron-demo\",\n    \"start:dev\": \"NODE_ENV=development NODE_PATH=./packages/hadron-demo nodemon --watch 'packages/hadron-demo/**/*.ts' --watch .rebuild.ts --ignore 'packages/hadron-demo/**/*.spec.ts' --exec 'ts-node' packages/hadron-demo/index.ts\",\n    \"start:test\": \"NODE_ENV=development NODE_PATH=./packages/hadron-demo ts-node packages/hadron-demo\",\n    \"start:lerna\": \"nodemon --watch 'packages/**/*.ts' --exec 'npm run build && touch .rebuild.ts' -e ts\",\n    \"build\": \"lerna bootstrap\",\n    \"prestart\": \"npm run build\",\n    \"precommit\": \"lint-staged\",\n    \"lint\": \"lerna exec --bail=false -- tslint -c \\\\$LERNA_ROOT_PATH/tslint.json -p ./tsconfig.json --format stylish\",\n    \"lint:fix\": \"lerna exec --bail=false -- tslint -c \\\\$LERNA_ROOT_PATH/tslint.json -p \\\\packages/$LERNA_PACKAGE_NAME/tsconfig.json --format stylish\",\n    \"test\": \"lerna bootstrap && npm run -s test:unit && npm run -s test:e2e\",\n    \"test:unit\": \"NODE_ENV=test NODE_PATH=src:lib mocha -r ts-node/register tools/testSetup.ts './**/__tests__/*.ts'\",\n    \"test:package\": \"./package-test.sh\",\n    \"test:unit:watch\": \"npm run test:unit -- --reporter min --watch-extensions ts --watch\",\n    \"test:unit:coverage\": \"NODE_ENV=test NODE_PATH=src:lib nyc mocha -r ts-node/register tools/testSetup.ts './**/__tests__/*.ts'\",\n    \"test:e2e\": \"./test.sh\",\n    \"test:cucumber\": \"NODE_ENV=test ./node_modules/.bin/cucumberjs --compiler=ts:ts-node/register\",\n    \"docker:build\": \"docker build -t brainhub-framework-app .\",\n    \"format\": \"prettier --write \\\"*/**/*.ts\\\"\",\n    \"tsc\": \"lerna exec tsc --parallel\",\n    \"clean\": \"bash ./scripts/clean\",\n    \"postinstall\": \"lerna bootstrap\"\n  },\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@types/bunyan\": \"1.8.4\",\n    \"body-parser\": \"1.18.2\",\n    \"dotenv\": \"4.0.0\",\n    \"mysql\": \"2.15.0\",\n    \"pg\": \"7.4.1\",\n    \"pm2\": \"github:Unitech/pm2#development\"\n  },\n  \"devDependencies\": {\n    \"@types/chai\": \"4.1.2\",\n    \"@types/chai-as-promised\": \"7.1.0\",\n    \"@types/cucumber\": \"4.0.1\",\n    \"@types/dotenv\": \"4.0.2\",\n    \"@types/fs-extra\": \"5.0.1\",\n    \"@types/mocha\": \"2.2.48\",\n    \"@types/multer\": \"1.3.6\",\n    \"@types/node\": \"9.4.6\",\n    \"@types/sinon\": \"4.1.3\",\n    \"@types/sinon-chai\": \"2.7.29\",\n    \"chai\": \"4.1.2\",\n    \"chai-as-promised\": \"7.1.1\",\n    \"concurrently\": \"3.5.1\",\n    \"cucumber\": \"3.1.0\",\n    \"@brainhubeu/cucumber-steps\": \"git+https://github.com/brainhubeu/cucumber-steps.git\",\n    \"dirty-chai\": \"2.0.1\",\n    \"husky\": \"0.14.3\",\n    \"lerna\": \"^2.9.0\",\n    \"lint-staged\": \"7.0.0\",\n    \"mocha\": \"4.0.1\",\n    \"nodemon\": \"1.12.1\",\n    \"nyc\": \"11.6.0\",\n    \"prettier\": \"1.11.1\",\n    \"reflect-metadata\": \"0.1.12\",\n    \"sinon\": \"4.1.2\",\n    \"sinon-chai\": \"2.14.0\",\n    \"superagent\": \"3.8.2\",\n    \"ts-node\": \"5.0.0\",\n    \"tslint\": \"5.9.1\",\n    \"tslint-config-airbnb\": \"5.7.0\",\n    \"tslint-config-prettier\": \"1.10.0\",\n    \"tslint-eslint-rules\": \"5.1.0\",\n    \"typescript\": \"2.7.2\"\n  },\n  \"nyc\": {\n    \"extension\": [\n      \".ts\"\n    ]\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"npm run lint:fix\",\n      \"git add\"\n    ],\n    \"*.{ts,js,json,css,md}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/brainhubeu/hadron.git\"\n  },\n  \"keywords\": [\n    \"hadron\"\n  ]\n}\n"
  },
  {
    "path": "packages/hadron-auth/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-auth/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-auth --save\n```\n\n## Overview\n\n**hadron-auth** provides back-end authorization layer for routes You will choose.\n\n### Configuration with Hadron Core\n\nIf You want to use **hadron-auth** with **hadron-core** You should also use **hadron-typeorm** and **hadron-express**.\nAll You need to provide is two schemas for typeorm:\n\n* `User` (id, username, and roles many-to-many relation required)\n  Here is the example schema:\n\n```javascript\n// schemas/User\nconst userSchema = {\n  name: 'User',\n  columns: {\n    id: {\n      primary: true,\n      type: 'int',\n      generated: true,\n    },\n    username: {\n      type: 'varchar',\n      unique: true,\n    },\n    passwordHash: {\n      type: 'varchar',\n    },\n    addedOn: {\n      type: 'timestamp',\n    },\n  },\n  relations: {\n    roles: {\n      target: 'Role',\n      type: 'many-to-many',\n      joinTable: {\n        name: 'user_role',\n      },\n      onDelete: 'CASCADE',\n    },\n  },\n};\n\nmodule.exports = userSchema;\n```\n\n* `Role` (id and name required)\n  Example schema:\n\n```javascript\n// schemas/Role\nconst roleSchema = {\n  name: 'Role',\n  columns: {\n    id: {\n      primary: true,\n      type: 'int',\n      generated: true,\n    },\n    name: {\n      type: 'varchar',\n      unique: true,\n    },\n    addedOn: {\n      type: 'timestamp',\n    },\n  },\n};\n\nmodule.exports = roleSchema;\n```\n\nDon't forget to add schemas to Your database config, example below:\n\n```javascript\n// config/db.js\nconst userSchema = require('../schemas/User');\nconst roleSchema = require('../schemas/Role');\n\nconst connection = {\n  name: 'mysql-connection',\n  type: 'mysql',\n  host: 'localhost',\n  port: 3306,\n  username: 'root',\n  password: 'my-secret-pw',\n  database: 'done-it',\n  entitySchemas: [roleSchema, userSchema],\n  synchronize: true,\n};\n\nmodule.exports = connection,\n```\n\nNow You need to prepare Your hadron configuration file, where You can add secured routes, for example:\n\n```javascript\n// index.js\nconst config = {\n  routes: {\n    helloWorldRoute: {\n      path: '/',\n      methods: ['GET'],\n      callback: () => 'Hello World',\n    },\n    adminRoute: {\n      path: '/admin',\n      methods: ['GET'],\n      callback: () => 'Hello Admin',\n    },\n    userRoute: {\n      path: '/user',\n      methods: ['GET'],\n      callback: () => 'Hello User',\n    },\n  },\n  securedRoutes: [\n    {\n      path: '/admin/*',\n      methods: ['GET', 'POST', 'PUT', 'DELETE'],\n      roles: 'Admin',\n    },\n    {\n      path: '/user/*',\n      roles: ['Admin', 'User'],\n    },\n  ],\n};\n```\n\nFinally You need to add **hadron-auth** to hadron initialization method:\n\n```javascript\nconst hadron = require('@brainhubeu/hadron-core').default;\nconst hadronExpress = require('@brainhubeu/hadron-express');\nconst hadronTypeOrm = require('@brainhubeu/hadron-typeorm');\nconst hadronAuth = require('@brainhubeu/hadron-auth');\nconst express = require('express');\n\nconst expressApp = express();\n\nconst hadronInit = async () => {\n  const config = {\n    routes: {\n      helloWorldRoute: {\n        path: '/',\n        methods: ['GET'],\n        callback: () => 'Hello World',\n      },\n      adminRoute: {\n        path: '/admin',\n        methods: ['GET'],\n        callback: () => 'Hello Admin',\n      },\n      userRoute: {\n        path: '/user',\n        methods: ['GET'],\n        callback: () => 'Hello User',\n      },\n    },\n    securedRoutes: [\n      {\n        path: '/admin/*',\n        methods: ['GET', 'POST', 'PUT', 'DELETE'],\n        roles: 'Admin',\n      },\n      {\n        path: '/user/*',\n        roles: ['Admin', 'User'],\n      },\n    ],\n  };\n\n  const container = await hadron(\n    expressApp,\n    [hadronAuth, hadronExpress, hadronTypeOrm],\n    config,\n  );\n};\n```\n\n---\n\nWarning, You should pass hadronAuth as first to hadron packages array.\n\n---\n\nNow Your routes are secured, by default, **hadron-auth** authorize user by **JWT Token**, passed as `Authorization` header.\n\n### Creating custom auth middleware\n\nYou can pass Your own function in hadron configuration to check if a user is authorized to the secured route.\nHere is the skeleton for the authorization middleware:\n\n```javascript\nconst authorizationMiddleware = (container) => {\n  return (req, res, next) => {};\n};\n```\n\n**hadron-auth** provides `isAllowed` function, to check if a user is allowed to specified route:\n\n```javascript\nisAllowed(path, method, user, allRoles);\n```\n\nWhere:\n\n* `path` - path to secured route, for example /api/admin/1\n* `method` - HTTP method\n* `user` - User object, which need to contain roles\n* `allRoles` - All roles stored in database (only role names)\n\nHere is an example authorization middleware:\n\n```javascript\nconst jwt = require('jsonwebtoken');\nconst { isRouteSecure, isAllowed } = require('@brainhubeu/hadron-auth');\n\nconst errorResponse = {\n  message: 'Unauthorized',\n};\n\nconst expressMiddlewareAuthorization = (container) => {\n  return async (req, res, next) => {\n    try {\n      if (!isRouteSecure(req.path)) {\n        return next();\n      }\n\n      const userRepository = container.take('userRepository');\n      const roleRepository = container.take('roleRepository');\n\n      const token = req.headers.authorization;\n\n      const decoded: any = jwt.decode(token);\n\n      const user = await userRepository.findOne({\n        where: { id: decoded.id },\n        relations: ['roles'],\n      });\n\n      if (!user) {\n        return res.status(403).json({ error: errorResponse });\n      }\n\n      const allRoles = await roleRepository.find();\n\n      if (\n        isAllowed(req.path, req.method, user, allRoles.map((role) => role.name))\n      ) {\n        return next();\n      }\n\n      return res.status(403).json({ error: errorResponse });\n    } catch (error) {\n      return res.status(403).json({ error: errorResponse });\n    }\n  };\n};\n\nmodule.exports = expressMiddlewareAuthorization;\n```\n\nTo use it, You need to pass an expressMiddlewareAuthorization function as `authorizationMiddleware` key in hadron config.\n\n```javascript\nconst config = {\n  authorizationMiddleware: YourCustomFunction,\n};\n```\n\n### Usage:\n\n```javascript\nconst securedRoutes = [\n  {\n    path: '/api/**',\n    methods: ['GET'],\n    roles: ['Admin', 'User'],\n  },\n  {\n    path: '/api/**',\n    methods: ['POST', 'PUT', 'DELETE'],\n    roles: 'Admin',\n  },\n  {\n    path: '/admin/*',\n    roles: 'Admin',\n  },\n  {\n    path: 'product/info',\n    methods: ['GET'],\n    roles: [['Admin', 'User'], 'Manager'],\n  },\n];\n```\n\n* `Path` - here we can specify the route path we want to secure, we can use a static path like `/api/admin/tasks` or by pattern:\n  * `/api/admin/*` - route after `/api/admin/` is secured, for example `/api/admin/tasks` - is secured, but `/api/admin/tasks/5` - will be not secured\n  * `/api/admin/**` - every route after `/api/admin` is secured\n* `methods` - an array of strings, where You can pass role names, if You will not provide any role, then the route is secured and user with **ANY** role can access this if a user does not have any role he will be unauthorized.\n* `roles` - here You can pass single role name, an array of role names or array of arrays of strings, which add some logic functionality, for example, if we declare:\n\n```javascript\nroles[(['Admin', 'User'], 'Manager')];\n```\n\nThe user needs Admin **AND** User **OR** Manager role to access the route.\n"
  },
  {
    "path": "packages/hadron-auth/index.ts",
    "content": "import { IUser, IRole } from './src/hierarchyProvider';\nimport * as bcrypt from './src/password/bcrypt/bcrypt';\nimport * as HadronAuth from './src/HadronAuth';\n\nexport const register = (container: any, config: any) => {\n  HadronAuth.register(container, config);\n};\n\nexport default HadronAuth;\nexport { IUser, IRole, bcrypt };\n"
  },
  {
    "path": "packages/hadron-auth/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-auth\",\n  \"version\": \"0.0.2\",\n  \"description\": \"Security package for hadron\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"security\",\n    \"hadron\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@types/bcrypt\": \"^2.0.0\",\n    \"@types/jsonwebtoken\": \"^7.2.7\",\n    \"bcrypt\": \"2.0.0\",\n    \"glob-to-regexp\": \"^0.4.0\",\n    \"jsonwebtoken\": \"8.3.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-auth/src/HadronAuth.ts",
    "content": "import { IRoute, IMethod } from './IRoute';\nimport urlGlob, { convertToPattern } from './helpers/urlGlob';\nimport { IUser } from '..';\nimport { isUserGranted } from './hierarchyProvider';\nimport expressMiddlewareAuthorization from './providers/expressMiddlewareAuthorization';\n\nlet routes: IRoute[] = [];\n\nexport interface ISecuredRoute {\n  path: string;\n  methods?: string[];\n  roles: string | Array<string | string[]>;\n}\n\nexport const getExistsingRoute = (path: string, routes: IRoute[]): IRoute => {\n  for (const route of routes) {\n    if (route.path === path) {\n      return route;\n    }\n  }\n\n  return null;\n};\n\nexport const getRoleArray = (roles: string | Array<string | string[]>) => {\n  const arr: any[] = [];\n  if (typeof roles === 'string') {\n    arr.push(roles);\n  } else {\n    roles.forEach((role) => arr.push(role));\n  }\n\n  return [...new Set(arr)];\n};\n\nexport const getMethodsForExistsingRoute = (\n  existingRoute: IRoute,\n  methods: string[],\n  roles: string | Array<string | string[]>,\n): IMethod[] => {\n  const newMethods: IMethod[] = methods.map((method) => ({\n    allowedRoles: getRoleArray(roles),\n    name: method,\n  }));\n\n  const existingMethods = existingRoute.methods.filter(\n    (method) => newMethods.map((el) => el.name).indexOf(method.name) >= 0,\n  );\n\n  const nonExistingMethods = newMethods.filter(\n    (method) =>\n      existingRoute.methods.map((el) => el.name).indexOf(method.name) === -1,\n  );\n\n  existingMethods.forEach((method) => {\n    method.allowedRoles = [\n      ...new Set(method.allowedRoles.concat(getRoleArray(roles))),\n    ];\n  });\n\n  let methodsFromRoute = existingRoute.methods.filter(\n    (method) =>\n      existingMethods.map((el) => el.name).indexOf(method.name) === -1,\n  );\n\n  methodsFromRoute = methodsFromRoute.concat(existingMethods);\n\n  return [...methodsFromRoute, ...nonExistingMethods];\n};\n\nexport const createNewRoute = (\n  path: string,\n  methods: string[] = [],\n  roles: string | Array<string | string[]>,\n) => {\n  const methodsForRoute: IMethod[] = [];\n\n  if (methods.length > 0) {\n    methods = [...new Set(methods)];\n    methods.forEach((methodName) => {\n      methodsForRoute.push({\n        name: methodName,\n        allowedRoles: getRoleArray(roles),\n      });\n    });\n  } else {\n    methodsForRoute.push({\n      name: '*',\n      allowedRoles: getRoleArray(roles),\n    });\n  }\n\n  const route: IRoute = {\n    path: convertToPattern(path),\n    methods: methodsForRoute,\n  };\n\n  return route;\n};\n\nexport const initRoutes = (securedRoutes: ISecuredRoute[]): IRoute[] => {\n  const routes: IRoute[] = [];\n  securedRoutes.forEach((route) => {\n    const existingRoute = getExistsingRoute(\n      convertToPattern(route.path),\n      routes,\n    );\n\n    if (existingRoute) {\n      existingRoute.methods = getMethodsForExistsingRoute(\n        existingRoute,\n        route.methods,\n        route.roles,\n      );\n    } else {\n      routes.push(createNewRoute(route.path, route.methods, route.roles));\n    }\n  });\n\n  return routes;\n};\n\nexport const register = (container: any, config: any) => {\n  if (config.authSecret) {\n    container.register('authSecret', config.authSecret);\n  }\n\n  routes = initRoutes(config.securedRoutes || []);\n  const server = container.take('server');\n\n  server.use(\n    config.authorizationMiddleware\n      ? config.authorizationMiddleware(container)\n      : expressMiddlewareAuthorization(container),\n  );\n};\n\nexport const getRouteFromPath = (path: string, routes: IRoute[]): IRoute => {\n  const route = routes.filter((r) => urlGlob(r.path, path));\n  if (route.length === 0) return null;\n  return route[0];\n};\n\nexport const isRouteNotSecure = (path: string) => {\n  console.warn(\"HadronAuth: isRouteNotSecure is being deprecated. Use isRouteSecure instead.\");\n  return getRouteFromPath(path, routes) === null;\n}\n\nexport const isRouteSecure = (path: string) =>\n  getRouteFromPath(path, routes) !== null;\n\nexport const isAllowed = (\n  path: string,\n  allowedMethod: string,\n  user: IUser,\n  allRoles: string[],\n): boolean => {\n  try {\n    const route = getRouteFromPath(path, routes);\n    let isGranted = false;\n\n    route.methods.forEach((method) => {\n      if (\n        method.name === '*' ||\n        method.name.toLowerCase() === allowedMethod.toLowerCase()\n      ) {\n        if (method.allowedRoles.includes('*') && user.roles.length > 0) {\n          isGranted = true;\n        } else {\n          isGranted = isUserGranted(user, method.allowedRoles, {\n            ALL: allRoles,\n          });\n        }\n      }\n    });\n    return isGranted;\n  } catch (error) {\n    throw new Error('Unauthorized');\n  }\n};\n"
  },
  {
    "path": "packages/hadron-auth/src/IRoute.ts",
    "content": "export interface IRoute {\n  path: string;\n  methods: IMethod[];\n}\n\nexport interface IMethod {\n  name: string;\n  allowedRoles: Array<string | string[]>;\n}\n"
  },
  {
    "path": "packages/hadron-auth/src/ISecurityOptions.ts",
    "content": "import { IRolesMap } from './hierarchyProvider';\nimport IHashMethod from './password/IHashMethod';\n\nexport default interface ISecurityOptions {\n  roles: IRolesMap | string[];\n  hash?: {\n    method: IHashMethod | string;\n    options: any;\n  };\n};\n"
  },
  {
    "path": "packages/hadron-auth/src/__tests__/HadronAuth.ts",
    "content": "import { expect } from 'chai';\nimport {\n  initRoutes,\n  ISecuredRoute,\n  getRouteFromPath,\n  getExistsingRoute,\n  createNewRoute,\n  getMethodsForExistsingRoute,\n} from '../HadronAuth';\nimport { convertToPattern } from '../helpers/urlGlob';\n\ndescribe('Hadron Authorization module', () => {\n  it('initRoutes should return array of prepared IRoute from ISecuredRoute array', () => {\n    const securedRoutes: ISecuredRoute[] = [\n      {\n        path: '/admin/**',\n        methods: ['POST', 'PUT'],\n        roles: ['Admin', 'User'],\n      },\n    ];\n\n    const routes = initRoutes(securedRoutes);\n\n    expect(routes).to.be.instanceOf(Array);\n    expect(Object.keys(routes[0])).to.be.deep.equal(['path', 'methods']);\n  });\n\n  it('initRoutes should join two same paths with different methods/roles', () => {\n    const securedRoutes: ISecuredRoute[] = [\n      {\n        path: '/admin/**',\n        methods: ['POST', 'PUT'],\n        roles: 'Admin',\n      },\n      {\n        path: '/admin/**',\n        methods: ['GET'],\n        roles: 'User',\n      },\n    ];\n\n    const routes = initRoutes(securedRoutes);\n\n    expect(routes.length).to.be.equal(1);\n    expect(Object.keys(routes[0])).to.be.deep.equal(['path', 'methods']);\n  });\n\n  it('initRoutes should convert path from securedRoute to regex pattern', () => {\n    const securedRoutes: ISecuredRoute[] = [\n      {\n        path: '/admin/*',\n        methods: ['POST'],\n        roles: 'Admin',\n      },\n    ];\n\n    const routes = initRoutes(securedRoutes);\n    const matcher = new RegExp(routes[0].path);\n    const testPath = '/admin/1';\n\n    expect(matcher.test('admin/1')).to.be.equal(true);\n  });\n\n  describe('getRouteFromPath', () => {\n    const routes = initRoutes([\n      {\n        path: '/admin/*',\n        methods: ['POST'],\n        roles: 'Admin',\n      },\n      {\n        path: '/user/*',\n        methods: ['POST'],\n        roles: 'Admin',\n      },\n    ]);\n\n    it('getRouteFromPath should return IRoute if path is already exists by regex in routes', () => {\n      expect(getRouteFromPath('/admin/1', routes)).to.be.an('object');\n    });\n\n    it('getRouteFromPath should return null if path does not exists by regex in routes', () => {\n      expect(getRouteFromPath('/qwe', routes)).to.be.equal(null);\n    });\n  });\n\n  describe('getExistingRoute', () => {\n    const routes = initRoutes([\n      {\n        path: '/admin/*',\n        methods: ['POST'],\n        roles: 'Admin',\n      },\n      {\n        path: '/user/*',\n        methods: ['POST'],\n        roles: 'Admin',\n      },\n    ]);\n\n    it('getExistingRoute should return route if route exists in array', () => {\n      expect(\n        getExistsingRoute(convertToPattern('/admin/*'), routes),\n      ).to.be.equal(routes[0]);\n    });\n\n    it('getExistingRoute should return null if route does not exists in array', () => {\n      expect(\n        getExistsingRoute(convertToPattern('/guest/*'), routes),\n      ).to.be.equal(null);\n    });\n  });\n\n  describe('createNewRoute', () => {\n    const path = '/admin/**';\n    const methods: string[] = [];\n    const roles = 'Admin';\n\n    const route = createNewRoute(path, methods, roles);\n    it('createNewRoute should create IRoute from path, methods and roles', () => {\n      expect(Object.keys(route)).to.be.deep.equal(['path', 'methods']);\n    });\n\n    it('createNewRoute should create regex pattern from path string', () => {\n      expect(route.path).to.be.equal(convertToPattern('/admin/**'));\n    });\n\n    it('createNewRoute should push \"*\" to methods array if array is empty', () => {\n      expect(route.methods[0].name).to.be.equal('*');\n    });\n\n    it('createNewRoute should create IMethod with name and roles in route object', () => {\n      expect(Object.keys(route.methods[0])).to.be.deep.equal([\n        'name',\n        'allowedRoles',\n      ]);\n    });\n  });\n\n  describe('getMethodsForExistingRoute', () => {\n    const path = '/admin/**';\n    const methods: string[] = ['GET'];\n    const roles = 'Admin';\n\n    const route = createNewRoute(path, methods, roles);\n\n    it('getMethodsForExistsinRoute should push new methods to existing route', () => {\n      const newMethods = getMethodsForExistsingRoute(\n        route,\n        ['POST', 'PUT'],\n        ['User', 'Admin', 'Guest'],\n      );\n\n      expect(newMethods.length).to.be.equal(3);\n    });\n\n    it('getMethodsForExistsinRoute should push new roles to existing method', () => {\n      const newMethods = getMethodsForExistsingRoute(\n        route,\n        ['GET'],\n        ['User', 'Guest'],\n      );\n\n      expect(newMethods.length).to.be.equal(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-auth/src/__tests__/hierarchyProvider.ts",
    "content": "import hierarchyProvider, {\n  fillMissingRoles,\n  checkRole,\n  checkRoles,\n  getDeeperRoles,\n  excludeRoles,\n} from '../hierarchyProvider';\nimport { expect } from 'chai';\n\ndescribe('hierarchyProvider', () => {\n  const basicHierarchy = {\n    ADMIN: ['USER', 'MANAGER'],\n    MANAGER: ['USER'],\n    GUEST: [],\n  };\n\n  describe('fillMissingRoles', () => {\n    it('should add missing roles from hierarchy', () => {\n      const roles = {\n        ROLE1: ['ROLE2', 'ROLE3'],\n        ROLE2: ['ROLE4'],\n      };\n      expect(fillMissingRoles(roles)).to.contain.keys([\n        'ROLE1',\n        'ROLE2',\n        'ROLE3',\n        'ROLE4',\n      ]);\n    });\n\n    it('should keep hierarchy of previously mentioned role', () => {\n      const roles = {\n        ROLE1: ['ROLE2', 'ROLE3'],\n        ROLE2: ['ROLE4'],\n      };\n      expect(fillMissingRoles(roles).ROLE2).to.eql(['ROLE4']);\n    });\n\n    it('should handle array as roles', () => {\n      const roles = ['ROLE1', 'ROLE2'];\n      expect(fillMissingRoles(roles)).to.contain.keys(['ROLE1', 'ROLE2']);\n    });\n  });\n\n  describe('checkRole', () => {\n    it('should return true if role is exactly the same as requested', () =>\n      expect(checkRole(['ADMIN'], 'ADMIN', basicHierarchy)).to.be.eql(true));\n\n    it('should return false if role is not exactly the same and does not contain it in hierarchy', () =>\n      expect(checkRole(['USER'], 'MANAGER', basicHierarchy)).to.be.eql(false));\n\n    it('should return true if role is not exactly the same but does contain it in hierarchy', () =>\n      expect(checkRole(['MANAGER'], 'USER', basicHierarchy)).to.be.eql(true));\n\n    it('should return true if one of roles is matching', () =>\n      expect(\n        checkRole(['MANAGER', 'USER'], 'MANAGER', basicHierarchy),\n      ).to.be.eql(true));\n\n    it('should return false if none of roles is matching', () =>\n      expect(checkRole(['MANAGER', 'USER'], 'ADMIN', basicHierarchy)).to.be.eql(\n        false,\n      ));\n\n    it('should return true if role is in hierarchy of user roles', () =>\n      expect(checkRole(['ADMIN', 'USER'], 'MANAGER', basicHierarchy)).to.be.eql(\n        true,\n      ));\n\n    it('should return true if role is in deeper hierarchy of user roles', () => {\n      const roles = {\n        ...basicHierarchy,\n        MANAGER: ['TESTUSER', 'USER'],\n      };\n      return expect(checkRole(['ADMIN'], 'TESTUSER', roles)).to.be.eql(true);\n    });\n\n    it('should handle recurrent hierarchy', () => {\n      const roles = {\n        ADMIN: ['MANAGER'],\n        MANAGER: ['ADMIN'],\n      };\n      return expect(checkRole(['ADMIN'], 'TESTUSER', roles)).to.be.eql(false);\n    });\n\n    it(\"should return false, if role doesn't exists\", () =>\n      expect(checkRole(['ADMIN'], 'UNEXISTING_ROLE', basicHierarchy)).to.be.eql(\n        false,\n      ));\n  });\n\n  describe('checkRoles', () => {\n    it('should return true if role is one of given', () =>\n      expect(\n        checkRoles(['MANAGER'], ['MANAGER', 'ADMIN'], basicHierarchy),\n      ).to.be.eql(true));\n\n    it('should return false, if none of roles is matching given one', () =>\n      expect(\n        checkRoles(['USER'], ['MANAGER', 'ADMIN'], basicHierarchy),\n      ).to.be.eql(false));\n\n    it('should return true if user has both roles', () =>\n      expect(\n        checkRoles(\n          ['MANAGER', 'ADMIN'],\n          ['MANAGER', 'ADMIN'],\n          basicHierarchy,\n          true,\n        ),\n      ).to.be.eql(true));\n\n    it(\"should return false if user doesn't have one of roles\", () =>\n      expect(\n        checkRoles(['MANAGER'], ['MANAGER', 'ADMIN'], basicHierarchy, true),\n      ).to.be.eql(false));\n\n    it('should return true if role contains both required roles', () =>\n      expect(\n        checkRoles(['ADMIN'], ['MANAGER', 'USER'], basicHierarchy, true),\n      ).to.be.eql(true));\n  });\n\n  describe('getDeeperRoles', () => {\n    it('should return roles that are related to given one', () =>\n      expect(getDeeperRoles(['ADMIN'], basicHierarchy)).to.has.members([\n        'MANAGER',\n        'USER',\n      ]));\n\n    it('should return roles that are related to all given roles', () => {\n      const hierarchy = {\n        ROLE1: ['ROLE2', 'ROLE3'],\n        ROLE4: ['ROLE5'],\n      };\n\n      return expect(\n        getDeeperRoles(['ROLE1', 'ROLE4'], hierarchy),\n      ).to.has.members(['ROLE2', 'ROLE3', 'ROLE5']);\n    });\n\n    it('should return roles that are related to all given roles distinctly', () => {\n      const hierarchy = {\n        ROLE1: ['ROLE2', 'ROLE3'],\n        ROLE4: ['ROLE5', 'ROLE3'],\n      };\n\n      return expect(\n        getDeeperRoles(['ROLE1', 'ROLE4'], hierarchy),\n      ).to.has.members(['ROLE2', 'ROLE3', 'ROLE5']);\n    });\n  });\n\n  describe('excludeRoles', () => {\n    it('should remove given role from list', () =>\n      expect(excludeRoles(['ADMIN'], basicHierarchy)).to.contain.keys([\n        'MANAGER',\n        'GUEST',\n      ]));\n\n    it('should remove given roles from list', () =>\n      expect(\n        excludeRoles(['ADMIN', 'MANAGER'], basicHierarchy),\n      ).to.contain.keys(['GUEST']));\n  });\n\n  describe('isGranted', () => {\n    const { isGranted } = hierarchyProvider(basicHierarchy);\n\n    it('should pass if single matching role has been provided', () =>\n      expect(isGranted(['ADMIN'], 'ADMIN')).to.be.eql(true));\n\n    it('should fail if single not matching role has been provided', () =>\n      expect(isGranted(['ADMIN'], 'GUEST')).to.be.eql(false));\n\n    it('should pass if array of roles has been provided, with single matching one', () =>\n      expect(isGranted(['ADMIN'], ['ADMIN', 'GUEST'])).to.be.eql(true));\n\n    it('should fail if array of roles has been provided, with none that matches', () =>\n      expect(isGranted(['MANAGER'], ['ADMIN', 'GUEST'])).to.be.eql(false));\n\n    it('should pass if array of arrays of roles has been provided and all of them are matching', () =>\n      expect(isGranted(['ADMIN', 'GUEST'], [['ADMIN', 'GUEST']])).to.be.eql(\n        true,\n      ));\n\n    it('should fail if array of arrays of roles has been provided and one of them is not matching', () =>\n      expect(isGranted(['ADMIN'], [['ADMIN', 'GUEST']])).to.be.eql(false));\n\n    it('should pass if array of arrays and single role has been provided and one of them are matching', () =>\n      expect(isGranted(['MANAGER'], [['ADMIN', 'GUEST'], 'MANAGER'])).to.be.eql(\n        true,\n      ));\n\n    it('should fail if array of arrays of roles has been provided and none of them are matching', () =>\n      expect(\n        isGranted(['MANAGER'], [['ADMIN', 'GUEST'], ['MANAGER', 'GUEST']]),\n      ).to.be.eql(false));\n\n    it('should pass if array of arrays of roles has been provided and one of them are matching', () =>\n      expect(\n        isGranted(\n          ['MANAGER', 'GUEST'],\n          [['ADMIN', 'GUEST'], ['MANAGER', 'GUEST']],\n        ),\n      ).to.be.eql(true));\n  });\n});\n"
  },
  {
    "path": "packages/hadron-auth/src/__tests__/urlGlob.ts",
    "content": "import { expect } from 'chai';\nimport urlGlob from '../helpers/urlGlob';\n\ndescribe('Glob URL pattern', () => {\n  it('should return true if URL: /api/admin/qwe is valid for PATTERN: /api/admin/*', () => {\n    expect(urlGlob('/api/admin/*', '/api/admin/qwe')).to.be.equal(true);\n  });\n\n  it('should return false if URL: /api/adm/qwe is invalid for PATTERN: /api/admin/*', () => {\n    expect(urlGlob('/api/admin/*', '/api/adm/qwe')).to.be.equal(false);\n  });\n\n  it('should return false if URL: /api/admin/qwe/1 is invalid for PATTERN: /api/admin/*', () => {\n    expect(urlGlob('/api/admin/*', '/api/adm/qwe')).to.be.equal(false);\n  });\n\n  it('should return true if URL: /api/admin/tasks/1 is valid for PATTERN: /api/admin/**', () => {\n    expect(urlGlob('/api/admin/**', '/api/admin/tasks/1')).to.be.equal(true);\n  });\n\n  it('should return true if URL: /api/something/admin/more/user/in/manager/string for PATTERN: /api/**/admin/**/manager/**', () => {\n    expect(\n      urlGlob(\n        '/api/**/admin/**/user/**/manager/**',\n        '/api/something/admin/more/user/in/manager/string',\n      ),\n    ).to.be.equal(true);\n  });\n\n  it('should return false if URL: /api/something/admin/more/user/in/mage/string for PATTERN: /api/**/admin/**/manager/**', () => {\n    expect(\n      urlGlob(\n        '/api/**/admin/**/user/**/manager/**',\n        '/api/something/admin/more/user/in/mage/string',\n      ),\n    ).to.be.equal(false);\n  });\n\n  it('should return false if URL: /api/something/admin/more is invalid for PATTERNL /api/**/user/**', () => {\n    expect(urlGlob('/api/**/admin/**', '/api/something/user/more')).to.be.equal(\n      false,\n    );\n  });\n\n  it('should return true if URL: /api/admin is valid for strict PATTERN /api/admin', () => {\n    expect(urlGlob('/api/admin', '/api/admin')).to.be.equal(true);\n  });\n\n  it('should return false if URL: /api/adm or /api.admin/1 is invalid for strict PATTERN /api/admin', () => {\n    expect(urlGlob('/api/admin', '/api/adm')).to.be.equal(false);\n    expect(urlGlob('/api/admin', '/api/admin/1')).to.be.equal(false);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-auth/src/constants.ts",
    "content": "export const CONTAINER_NAME = 'isGranted';\n"
  },
  {
    "path": "packages/hadron-auth/src/declarations.d.ts",
    "content": "declare module 'glob-to-regexp';\n"
  },
  {
    "path": "packages/hadron-auth/src/helpers/flattenDeep.ts",
    "content": "const flattenDeep = (arr: any[]): any[] =>\n  Array.isArray(arr)\n    ? arr.reduce((a, b) => [...flattenDeep(a), ...flattenDeep(b)], [])\n    : [arr];\n\nexport default flattenDeep;\n"
  },
  {
    "path": "packages/hadron-auth/src/helpers/urlGlob.ts",
    "content": "const countStars = (input: string) => {\n  try {\n    return input.match(/\\*\\*/g).length;\n  } catch (error) {\n    return 0;\n  }\n};\n\nexport const convertToPattern = (url: string): string => {\n  const regexp = url[0] === '/' ? url.substring(1) : url;\n  if (url.endsWith('/*') && countStars(url) === 0) {\n    return `^/?${regexp.replace(/\\/\\*/g, '($|/$|/[^/]*$)')}$`;\n  }\n  if (url.endsWith('/**') && countStars(url) === 1) {\n    return `^/?${regexp.replace(/\\/\\*\\*/g, '($|/.*$)')}$`;\n  }\n\n  if (countStars(url) === 0) {\n    return `^/?${url}$`;\n  }\n\n  return convertToPattern(regexp.replace('**', '[^/]*'));\n};\n\nconst urlGlob = (pattern: string, input: string): boolean => {\n  const re = new RegExp(convertToPattern(pattern));\n  return re.test(input);\n};\n\nexport default urlGlob;\n"
  },
  {
    "path": "packages/hadron-auth/src/hierarchyProvider.ts",
    "content": "export interface IRolesMap {\n  [s: string]: string[];\n}\n\nexport interface IRole {\n  id: number | string;\n  name: string;\n}\n\nexport interface IUser {\n  id: number | string;\n  username: string;\n  passwordHash: string;\n  roles: IRole[];\n}\n\n/**\n * Function adds roles from dependency of other roles, to make sure that all roles are available\n * @param roles available roles with all \"dependent\" ones\n * @returns {IRolesMap}\n */\nexport function fillMissingRoles(roles: IRolesMap | string[]): IRolesMap {\n  if (roles instanceof Array) {\n    return roles.reduce(\n      (accumulator: IRolesMap, role: string) => ({\n        ...accumulator,\n        [role]: [],\n      }),\n      {},\n    );\n  }\n  return Object.entries(roles).reduce(\n    (accumulator: IRolesMap, [key, value]: [string, string[]]) => {\n      accumulator[key] = value;\n      value.forEach((role: string) => {\n        if (!accumulator[role]) {\n          accumulator[role] = [];\n        }\n      });\n      return accumulator;\n    },\n    {} as IRolesMap,\n  );\n}\n\n/**\n * Get array of all roles below in hierarchy distinctly\n * @param userRoles\n * @param availableRoles\n * @returns {string[]}\n */\nexport function getDeeperRoles(userRoles: string[], availableRoles: IRolesMap) {\n  return userRoles\n    .filter((role: string) => !!availableRoles[role])\n    .reduce(\n      (accumulator: string[], role: string) => [\n        ...accumulator,\n        ...availableRoles[role].filter(\n          (roleToAdd) => !accumulator.includes(roleToAdd),\n        ),\n      ],\n      [],\n    );\n}\n\n/**\n * Returns array of all given roles, without ones given in first parameter\n * @param userRoles\n * @param availableRoles\n * @returns {string[]}\n */\nexport function excludeRoles(userRoles: string[], availableRoles: IRolesMap) {\n  return Object.entries(availableRoles)\n    .filter(([key, value]: [string, any]) => userRoles.indexOf(key) < 0)\n    .reduce(\n      (accumulator: object, [key, value]: [string, any]) => ({\n        ...accumulator,\n        [key]: value,\n      }),\n      {},\n    );\n}\n\n/**\n * Checks if user role contains required role\n * @param userRoles\n * @param requiredRole\n * @param availableRoles\n * @returns {boolean}\n */\nexport function checkRole(\n  userRoles: string[],\n  requiredRole: string,\n  availableRoles: IRolesMap,\n): boolean {\n  if (userRoles.length <= 0) {\n    return false;\n  }\n\n  if (userRoles.indexOf(requiredRole) >= 0) {\n    return true;\n  }\n\n  return checkRole(\n    getDeeperRoles(userRoles, availableRoles),\n    requiredRole,\n    // excludes currently checked roles to avoid endless recurrency\n    excludeRoles(userRoles, availableRoles),\n  );\n}\n\n/**\n * Checks list of roles\n *\n * @param userRoles\n * @param requiredRoles\n * @param availableRoles\n * @param exact specifies if user needs all roles from requiredRoles (true), or only one of them (false)\n * @return {boolean}\n */\nexport function checkRoles(\n  userRoles: string[],\n  requiredRoles: string[],\n  availableRoles: IRolesMap,\n  exact = false,\n): boolean {\n  if (userRoles.length <= 0) {\n    return false;\n  }\n\n  return requiredRoles\n    .map(\n      (role) =>\n        typeof role === 'object'\n          ? checkRoles(userRoles, role, availableRoles, true)\n          : checkRole(userRoles, role, availableRoles),\n    )\n    .reduce(\n      (accumulator, currentValue) =>\n        exact ? accumulator && currentValue : accumulator || currentValue,\n    );\n}\n\n/**\n * Returns true if given roles are matching expected roles in hierarchy\n * @param {IUser} user\n * @param roles\n * @param allRoles\n * @returns {boolean}\n */\nexport function isGranted(\n  userRoles: string[],\n  roles: any,\n  allRoles: IRolesMap,\n): boolean {\n  if (typeof roles === 'string') {\n    return checkRole(userRoles, roles, allRoles);\n  }\n\n  if (typeof roles === 'object') {\n    return checkRoles(userRoles, roles, allRoles);\n  }\n\n  throw new Error('Unknown role type');\n}\n\n/**\n * Returns true if user has matching role in hierarchy\n * @param {IUser} user\n * @param roles\n * @param allRoles\n * @returns {boolean}\n */\nexport function isUserGranted(\n  user: IUser,\n  roles: any,\n  allRoles: IRolesMap,\n): boolean {\n  return isGranted(user.roles.map((role) => role.name), roles, allRoles);\n}\n\n/**\n * Provider for hierarchy manager\n * @param rolesHierarchy\n * @returns {function<boolean>}\n */\nexport default function hierarchyProvider(\n  rolesHierarchy: IRolesMap | string[],\n) {\n  const fullRoles: IRolesMap = fillMissingRoles(rolesHierarchy);\n  return {\n    isGranted: (userRoles: string[], roles: any) =>\n      isGranted(userRoles, roles, fullRoles),\n    isUserGranted: (user: IUser, roles: any) =>\n      isUserGranted(user, roles, fullRoles),\n  };\n}\n"
  },
  {
    "path": "packages/hadron-auth/src/password/IHashMethod.ts",
    "content": "export default interface IHashMethod {\n  hash(password: string, salt?: string, options?: object): Promise<string>;\n  compare(\n    userPassword: string,\n    hashedPassword: string,\n    salt?: string,\n    options?: object,\n  ): Promise<boolean>;\n};\n"
  },
  {
    "path": "packages/hadron-auth/src/password/__tests__/hashMethodProvider.ts",
    "content": "import hashMethodProvider from '../hashMethodProvider';\nimport { expect } from 'chai';\nimport * as sinon from 'sinon';\n\nimport ISecurityOptions from '../../ISecurityOptions';\nimport IHashMethod from '../IHashMethod';\n\ndescribe('hashMethodProvider', () => {\n  const defaultOptions = {\n    roles: [],\n  } as ISecurityOptions;\n\n  it('should return bcrypt on default', () => {\n    const bcryptSpy = sinon.spy();\n\n    hashMethodProvider(defaultOptions, { bcrypt: bcryptSpy });\n    return expect(bcryptSpy.calledOnce).to.be.equal(true);\n  });\n\n  it('should return method, which name was defined in config', () => {\n    const testSpy = sinon.spy();\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method: 'testMethod',\n      },\n    } as ISecurityOptions;\n\n    hashMethodProvider(options, { testMethod: testSpy });\n    return expect(testSpy.calledOnce).to.be.equal(true);\n  });\n\n  it(\"should return default method, if method name from config doesn't exists\", () => {\n    const bcryptSpy = sinon.spy();\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method: 'testMethod',\n      },\n    } as ISecurityOptions;\n\n    hashMethodProvider(options, { bcrypt: bcryptSpy });\n    return expect(bcryptSpy.calledOnce).to.be.equal(true);\n  });\n\n  it('should return method defined in config', () => {\n    const hashStub = sinon.spy();\n    const method = {\n      hash: hashStub,\n      compare: (userPassword: string, hashedPassword: string) =>\n        Promise.resolve(true),\n    } as IHashMethod;\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method,\n      },\n    } as ISecurityOptions;\n\n    hashMethodProvider(options).hash('smth');\n\n    return expect(hashStub.calledOnce).to.be.equal(true);\n  });\n\n  it('should return default method, if hash method defined in config is incorrect', () => {\n    const bcryptSpy = sinon.spy();\n    const method = {\n      hassh: (userPassword: string, hashedPassword: string) =>\n        Promise.resolve(true),\n      compaare: (userPassword: string, hashedPassword: string) =>\n        Promise.resolve(true),\n    };\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method,\n      },\n    };\n\n    hashMethodProvider(options as any, { bcrypt: bcryptSpy });\n\n    return expect(bcryptSpy.calledOnce).to.be.equal(true);\n  });\n\n  it('should pass options to hash method call of hashMethod', () => {\n    const hashStub = sinon.spy();\n    const method = {\n      hash: hashStub,\n      compare: (userPassword: string, hashedPassword: string) =>\n        Promise.resolve(true),\n    } as IHashMethod;\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method,\n        options: { lorem: 'ipsum' },\n      },\n    } as ISecurityOptions;\n\n    hashMethodProvider(options).hash('smth');\n\n    return expect(\n      hashStub.calledWith('smth', undefined, { lorem: 'ipsum' }),\n    ).to.be.equal(true);\n  });\n\n  it('should pass options to compare method call of hashMethod', () => {\n    const compareStub = sinon.spy();\n    const method = {\n      hash: (userPassword: string) => Promise.resolve('password'),\n      compare: compareStub,\n    } as IHashMethod;\n\n    const options = {\n      ...defaultOptions,\n      hash: {\n        method,\n        options: { lorem: 'ipsum' },\n      },\n    } as ISecurityOptions;\n\n    hashMethodProvider(options).compare('simple', 'hashed');\n\n    return expect(\n      compareStub.calledWith('simple', 'hashed', undefined, { lorem: 'ipsum' }),\n    ).to.be.equal(true);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-auth/src/password/bcrypt/IBcryptOptions.ts",
    "content": "export default interface IBcryptOptions {\n  saltRounds?: number;\n};\n"
  },
  {
    "path": "packages/hadron-auth/src/password/bcrypt/__tests__/bcrypt.ts",
    "content": "import { hash, compare } from '../bcrypt';\nimport * as bcrypt from 'bcrypt';\nimport { expect } from 'chai';\nimport * as sinon from 'sinon';\n\ndescribe('bcrypt', () => {\n  describe('hash', () => {\n    let hashStub: any = null;\n    let genSaltStub: any = null;\n\n    before(() => {\n      hashStub = sinon.stub(bcrypt, 'hash');\n      genSaltStub = sinon.stub(bcrypt, 'genSalt');\n    });\n\n    beforeEach(() => {\n      hashStub.reset();\n      genSaltStub.reset();\n      hashStub.returns(Promise.resolve('h45h'));\n      genSaltStub.returns(Promise.resolve('54lt'));\n    });\n\n    after(() => {\n      hashStub.restore();\n      genSaltStub.restore();\n    });\n\n    it('should run bcrypt hash method, if salt given', () => {\n      const password = 'loremIpsum';\n      const salt = 'd0n7-b3-s0-s4l7y';\n      return hash(password, salt).then(() =>\n        expect(hashStub.calledWithExactly(password, salt)).to.be.equal(true),\n      );\n    });\n\n    it('should generate salt if none given', () => {\n      const password = 'loremIpsum';\n      return hash(password, null).then(() =>\n        expect(hashStub.calledWithExactly(password, '54lt')).to.be.equal(true),\n      );\n    });\n\n    it('should run genSalt method of bcrypt, if no salt was passed', () => {\n      const password = 'loremIpsum';\n      return hash(password, null).then(() =>\n        expect(genSaltStub.calledWith()).to.be.equal(true),\n      );\n    });\n\n    it('should run genSalt method of bcrypt, if no salt was passed, with saltRound property from options', () => {\n      const password = 'loremIpsum';\n      const options = {\n        saltRounds: 12,\n      };\n      return hash(password, null, options).then(() =>\n        expect(genSaltStub.calledWithExactly(12)).to.be.equal(true),\n      );\n    });\n  });\n\n  describe('compare', () => {\n    let compareStub: any = null;\n\n    before(() => {\n      compareStub = sinon.stub(bcrypt, 'compare');\n    });\n\n    beforeEach(() => {\n      compareStub.reset();\n      compareStub.returns(Promise.resolve(true));\n    });\n\n    after(() => {\n      compareStub.restore();\n    });\n\n    it('should run compare method', () =>\n      compare('loremIpsum', 'loremIpsum1').then(() =>\n        expect(\n          compareStub.calledWithExactly('loremIpsum', 'loremIpsum1'),\n        ).to.be.equal(true),\n      ));\n\n    it('should resolves with true if passwords are matching', () =>\n      expect(compare('loremIpsum', 'loremIpsum1')).to.be.eventually.equal(\n        true,\n      ));\n\n    it('should resolves with false if passwords are not matching', () => {\n      compareStub.returns(Promise.resolve(false));\n      return expect(\n        compare('loremIpsum', 'loremIpsum1'),\n      ).to.be.eventually.equal(false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-auth/src/password/bcrypt/bcrypt.ts",
    "content": "import * as bcrypt from 'bcrypt';\nimport IHashMethod from '../IHashMethod';\nimport IBcryptOptions from './IBcryptOptions';\n\nexport function hash(\n  password: string,\n  salt?: string,\n  options: IBcryptOptions = {},\n): Promise<string> {\n  if (!salt) {\n    return bcrypt\n      .genSalt(options.saltRounds)\n      .then((salt) => bcrypt.hash(password, salt));\n  }\n  return bcrypt.hash(password, salt);\n}\n\nexport function compare(\n  userPassword: string,\n  hashedPassword: string,\n  options?: IBcryptOptions,\n): Promise<boolean> {\n  return bcrypt.compare(userPassword, hashedPassword);\n}\n\nexport default function bcryptProvider(options: IBcryptOptions): IHashMethod {\n  return {\n    hash: (password: string, salt?: string) => hash(password, salt, options),\n    compare: (userPassword: string, hashedPassword: string) =>\n      compare(userPassword, hashedPassword, options),\n  } as IHashMethod;\n}\n"
  },
  {
    "path": "packages/hadron-auth/src/password/hashMethodProvider.ts",
    "content": "import bcrypt from './bcrypt/bcrypt';\nimport ISecurityOptions from '../ISecurityOptions';\nimport IHashMethod from './IHashMethod';\n\nexport interface IHashProviderMap {\n  [s: string]: (options?: object) => IHashMethod;\n}\n\nconst availableMethod: IHashProviderMap = {\n  bcrypt,\n};\n\n/**\n * Function checks if given object is implementing IHashMethod interface\n * @param {IHashMethod | string} hashMethod\n * @returns {boolean}\n */\nfunction isHashMethod(\n  hashMethod: IHashMethod | string,\n): hashMethod is IHashMethod {\n  return (\n    (hashMethod as IHashMethod).compare !== undefined &&\n    (hashMethod as IHashMethod).hash !== undefined\n  );\n}\n\n/**\n * Funtion exctracts hashing method from config. Bcrypt on default.\n * @param config\n * @param methods\n */\nexport default function hashMethodProvider(\n  config: ISecurityOptions,\n  methods?: IHashProviderMap,\n) {\n  const allMethods: IHashProviderMap = { ...availableMethod, ...methods };\n  if (config.hash) {\n    const { method, options } = config.hash;\n\n    if (typeof method === 'string' && allMethods[method]) {\n      return allMethods[method](options);\n    }\n\n    if (isHashMethod(method)) {\n      return {\n        hash: (password: string, salt?: string) =>\n          method.hash(password, salt, options),\n        compare: (\n          userPassword: string,\n          hashedPassword: string,\n          salt?: string,\n        ) => method.compare(userPassword, hashedPassword, salt, options),\n      };\n    }\n  }\n\n  return allMethods.bcrypt();\n}\n"
  },
  {
    "path": "packages/hadron-auth/src/providers/expressMiddlewareAuthorization.ts",
    "content": "import * as jwt from 'jsonwebtoken';\nimport { isRouteSecure, isAllowed } from '../HadronAuth';\n\nconst errorResponse = {\n  message: 'Unauthorized',\n};\n\nconst expressMiddlewareAuthorization = (container: any) => {\n  return async (req: any, res: any, next: any) => {\n    try {\n      if (!isRouteSecure(req.path)) {\n        return next();\n      }\n\n      const userRepository = container.take('userRepository');\n      const roleRepository = container.take('roleRepository');\n\n      const token = req.headers.authorization.split(' ')[1];\n      const secret = container.take('authSecret');\n\n      const id: any = jwt.verify(token, secret);\n\n      const user = await userRepository.findOne({\n        where: { id },\n        relations: ['roles'],\n      });\n\n      if (!user) {\n        return res.status(401).json({ error: errorResponse });\n      }\n\n      const allRoles = await roleRepository.find();\n\n      if (\n        // @ts-ignore\n        isAllowed(req.path, req.method, user, allRoles.map((role) => role.name))\n      ) {\n        return next();\n      }\n\n      return res.status(401).json({ error: errorResponse });\n    } catch (error) {\n      return res.status(401).json({ error: errorResponse });\n    }\n  };\n};\n\nexport default expressMiddlewareAuthorization;\n"
  },
  {
    "path": "packages/hadron-auth/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"allowJs\": true,\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"src/__tests__/**\"]\n}\n"
  },
  {
    "path": "packages/hadron-core/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-core/README.md",
    "content": "## Installation\n\n* Install Node.js. We recommend using the latest version, installation details on [nodejs.org](https://nodejs.org)\n\n* Install following modules from npm:\n\n```bash\nnpm install @brainhubeu/hadron-core @brainhubeu/hadron-express express --save\n```\n\n## Hello world app\n\nLet's start with traditional Hello World app. It will give you a quick grasp of the framework.\n\n```javascript\nconst hadron = require('@brainhubeu/hadron-core').default;\nconst express = require('express');\n\nconst port = 8080;\nconst expressApp = express();\n\nconst config = {\n  routes: {\n    helloWorldRoute: {\n      path: '/',\n      callback: () => 'Hello world!',\n      methods: ['get'],\n    },\n  },\n};\n\nhadron(expressApp, [require('@brainhubeu/hadron-express')], config).then(() => {\n  expressApp.listen(port, () =>\n    console.log(`Listening on http://localhost:${port}`),\n  );\n});\n```\n\nIn the sections below, we will describe step by step what just happened.\n\n## Bootstrapping an app\n\nThe main hadron-core function is responsible for bootstrapping the app. It registers packages based on passed config and server instance:\n\n```javascript\nconst hadron = require('hadron-core').default;\n\nhadron(serverInstance, [...packages], config);\n```\n\nThe purpose of the main function is to initialize DI container and register package dependencies according to correspondent sections in config object (described in details in next chapters).\n\nMain function returns a promise that resolves to created DI container instance. In the promise `.then()` method, besides performing operations on the container instance, we can actually start our server, by calling Express `listen` method:\n\n```javascript\nhadron(serverInstance, ...rest).then((container) => {\n  // do some things on container...\n\n  serverInstance.listen(PORT, callback);\n});\n```\n\nNow, let's move to DI container itself.\n\n## Dependency Injection\n\nThe whole framework is built around DI Container concept. Its purpose is to automatically supply proper arguments for routes callbacks and other framework's building blocks.\n\nDI container instance is created and used internally by bootstrapping function, it is also returned (as a promise) from bootstrapping function, as mentioned in the previous section.\n\n### Container methods\n\n#### Registering items\n\n```javascript\ncontainer.register(key, item, lifetime);\n```\n\n* `key` - item name on which it will be registered inside the container\n* `item` - any value (primitive, data structure, function, class, etc.)\n* `lifetime` - the type of item's life-span\n\nLifetime options:\n\n* `'value'` - container returns registered item as is [default]\n* `'singleton'` - returns always the same instance of registered class / constructor function\n* `'transient'` - returns always a new instance of registered class / constructor function\n\n#### Retrieving items\n\n```javascript\ncontainer.take(key);\n```\n\n* `key` - item name (same as provided during registration)\n\nThe method returns item or item instance according to item type and lifetime option.\n\n#### Example usage in bootstrapping function\n\n```javascript\nconst { default: hadron, Lifetime } = require('hadron-core');\n\nhadron(...args).then((container) => {\n  container.register('foo', 123);\n  container.register('bar', class Bar {}, Lifetime.Singleton);\n  container.register('baz', class Baz {}, Lifetime.Transient);\n\n  // other stuff...\n});\n```\n\n### Accessing container items from routes' callbacks\n\nTo access container items from callbacks, you can just set arguments' names to match container keys, and required dependency will be provided.\n\nSee an example [here](../routing/#retrieving-items-from-container-in-callback)\n"
  },
  {
    "path": "packages/hadron-core/index.ts",
    "content": "import hadronCore from './src/hadronCore';\nexport { default as Container } from './src/container/container';\nexport * from './src/container/lifecycle';\nexport * from './src/container/types';\nexport default hadronCore;\n"
  },
  {
    "path": "packages/hadron-core/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-core\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hadron core module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-core\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-error-handler\": \"^1.0.0\",\n    \"@brainhubeu/hadron-utils\": \"^1.0.0\",\n    \"bunyan\": \"^1.8.12\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-core/src/__tests__/hadronCore.test.ts",
    "content": "import { expect } from 'chai';\nimport * as sinon from 'sinon';\nimport container from '../container/container';\n\nimport hadronCore, { prepareConfig } from '../hadronCore';\n\ndescribe('prepareConfig()', () => {\n  const logger = { error: sinon.spy() };\n  const defaultConfig = { prop1: 1, prop2: 2 };\n\n  it('should accept object', () => {\n    const config = { prop2: 4, prop3: 5 };\n    const expectedResult = { prop1: 1, prop2: 4, prop3: 5 };\n    return prepareConfig(defaultConfig, config, logger).then((resolvedConfig) =>\n      expect(resolvedConfig).to.deep.equal(expectedResult),\n    );\n  });\n\n  it('should accept promise, which returns object', () => {\n    const config = new Promise((res, rej) => res({ prop2: 4, prop3: 5 }));\n    const expectedResult = { prop1: 1, prop2: 4, prop3: 5 };\n    return prepareConfig(defaultConfig, config, logger).then((resolvedConfig) =>\n      expect(resolvedConfig).to.deep.equal(expectedResult),\n    );\n  });\n\n  it('should log error when config promise is rejected', () => {\n    const config = new Promise((res, rej) => rej());\n    const loggerMock = { error: sinon.spy() };\n    return prepareConfig(defaultConfig, config, loggerMock).catch((error) =>\n      expect(loggerMock.error.called).to.be.eql(true),\n    );\n  });\n\n  it('should return default config when config promise is rejected', () => {\n    const config = new Promise((res, rej) => rej());\n    return prepareConfig(defaultConfig, config, logger).then((resolvedConfig) =>\n      expect(resolvedConfig).to.deep.equal(defaultConfig),\n    );\n  });\n});\n\ndescribe('hadronCore()', () => {\n  const mockRegister = sinon.stub(container, 'register');\n\n  beforeEach(() => {\n    return mockRegister.reset();\n  });\n\n  after(() => {\n    return mockRegister.restore();\n  });\n\n  it('should return promise with Container instance', () => {\n    return hadronCore({}).then((returnedContainer) =>\n      expect(returnedContainer).to.equal(container),\n    );\n  });\n\n  it('should register server in container', () => {\n    const server = { call: 'I am server!' };\n    return hadronCore(server).then((returnedContainer) =>\n      expect(mockRegister.calledWith('server', server)).to.be.eql(true),\n    );\n  });\n\n  it('should run register function from given package', () => {\n    const server = { call: 'I am server!' };\n    const mockPackage = { register: sinon.spy() };\n    return hadronCore(server, [mockPackage]).then((returnedContainer) =>\n      expect(mockPackage.register.calledOnce).to.be.eql(true),\n    );\n  });\n\n  it('should include given config to hadron configuration and pass it to register function of package', () => {\n    const testConfig = {\n      testField: 'I am test!',\n    };\n    const server = { call: 'I am server!' };\n    const mockPackage = { register: sinon.spy() };\n    return hadronCore(server, [mockPackage], testConfig).then(\n      (returnedContainer) =>\n        // second argument, which should be config\n        expect(mockPackage.register.args[0][1]).to.contain(testConfig),\n    );\n  });\n});\n"
  },
  {
    "path": "packages/hadron-core/src/constants/eventNames.ts",
    "content": "export enum eventNames {\n  HANDLE_INITIALIZE_APPLICATION_EVENT = 'handleInitializeApplicationEvent',\n  HANDLE_TERMINATE_APPLICATION_EVENT = 'handleTerminateApplicationEvent',\n}\n"
  },
  {
    "path": "packages/hadron-core/src/container/__tests__/container.ts",
    "content": "/* tslint:disable:max-classes-per-file */\nimport { expect } from 'chai';\nimport container from '../container';\nimport { Lifecycle } from '../lifecycle';\n\ndescribe('container register', () => {\n  it('should overrive value for the the same key', () => {\n    const itemName = 'test';\n    container.register(itemName, 'given');\n    container.register(itemName, 'given2');\n    expect('given2').to.equal(container.take(itemName));\n  });\n  it('should always return the same object - Singleton', () => {\n    const itemName = 'test';\n    class Foo {\n      public value: string;\n      constructor() {\n        this.value = new Date().getTime().toString();\n      }\n    }\n    container.register(itemName, Foo, Lifecycle.Singleton);\n    const item1 = container.take(itemName);\n    const item2 = container.take(itemName);\n    expect(item2).to.deep.equal(item1);\n  });\n  it('should always return a new same object - Transient', () => {\n    class Foo {\n      public value: string;\n      constructor() {\n        this.value = 'xxxx';\n      }\n    }\n    container.register('test', Foo, Lifecycle.Transient);\n    const item1 = container.take('test');\n    const item2 = container.take('test');\n    expect(item1).to.deep.equal(item2);\n  });\n});\ndescribe('container items with parameters in constructor', () => {\n  it('second level of injection', () => {\n    class Foo {\n      public value: number;\n      constructor() {\n        this.value = 4;\n      }\n    }\n    class Foo2 {\n      public value: number;\n      constructor(parameterName: Foo) {\n        this.value = parameterName.value;\n      }\n    }\n    container.register('parameterName', Foo, Lifecycle.Transient);\n    container.register('foo2', Foo2, Lifecycle.Transient);\n\n    const item = container.take('parameterName') as Foo;\n\n    expect(4).to.be.equal(item.value);\n  });\n});\ndescribe(\"list of container's items keys \", () => {\n  it('should return array of keys of earlier registered items', () => {\n    container.register('key1', 'item1');\n    container.register('key2', 'item2');\n    const keys = container.keys();\n    expect(keys).to.include('key1');\n    expect(keys).to.include('key2');\n  });\n});\n"
  },
  {
    "path": "packages/hadron-core/src/container/__tests__/containerItem.ts",
    "content": "/* tslint:disable:max-classes-per-file */\nimport { expect } from 'chai';\nimport containerItem from '../containerItem';\nimport { Lifecycle } from '../lifecycle';\n\ndescribe('containerItem set lifecycle', () => {\n  it('should be default(value)', () => {\n    const item = containerItem.containerItemFactory('object', Object);\n    expect(item.constructor.name).to.equal('ContainerItem');\n  });\n  it('should be transient', () => {\n    const item = containerItem.containerItemFactory(\n      'object1',\n      Object,\n      'transient',\n    );\n    expect(item.constructor.name).to.equal('ContainerItemTransient');\n  });\n  it('should be singleton', () => {\n    const item = containerItem.containerItemFactory(\n      'object2',\n      Object,\n      Lifecycle.Singleton,\n    );\n    expect(item.constructor.name).to.equal('ContainerItemSingleton');\n  });\n});\ndescribe('containerItem set value', () => {\n  it('should return 1', () => {\n    const item = containerItem.containerItemFactory('number', 5);\n    expect(item.Item).to.equal(5);\n  });\n  it(\"should return 'oko'\", () => {\n    const item = containerItem.containerItemFactory('string', 'oko');\n    expect(item.Item).to.equal('oko');\n  });\n  it(\"should return '{}'\", () => {\n    const item = containerItem.containerItemFactory('object', {});\n    expect(item.Item).to.deep.equal({});\n  });\n\n  it('should return the same object twice', () => {\n    class Foo {\n      public value: string;\n      constructor() {\n        this.value = new Date().getTime().toString();\n      }\n    }\n    const item = containerItem.containerItemFactory(\n      'Fooooo',\n      Foo,\n      Lifecycle.Singleton,\n    );\n    const item1 = item.Item;\n    const item2 = item.Item;\n    expect(item1).to.equal(item2);\n  });\n  it('should always return new instance of given type', (done) => {\n    class Foo {\n      public value: string;\n      constructor() {\n        this.value = new Date().getTime().toString();\n      }\n    }\n    const item = containerItem.containerItemFactory(\n      'Foo',\n      Foo,\n      Lifecycle.Transient,\n    );\n    const item1 = item.Item;\n\n    setTimeout(() => {\n      const item2 = item.Item;\n      expect(item1.value).to.not.equal(item2.value);\n      done();\n    }, 10);\n  });\n  it('should always return new instance of given type 2', () => {\n    class Foo {\n      public value: string;\n      constructor() {\n        this.value = new Date().getTime().toString();\n      }\n    }\n    const item = containerItem.containerItemFactory(\n      'Foo',\n      Foo,\n      Lifecycle.Transient,\n    );\n    const item1 = item.Item;\n    const item2 = item.Item;\n    expect(item1).to.not.equal(item2);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-core/src/container/container.ts",
    "content": "import containerItem from './containerItem';\nimport { IContainerItem, IContainer } from './types';\nimport isVarName from '../helpers/isVarName';\nimport IncorrectContainerKeyNameError from '../errors/IncorrectContainerKeyNameError';\n\nconst containerRegister = new Array<IContainerItem>();\n\nconst takeContainerByKey = (key: string): IContainerItem[] =>\n  containerRegister.filter((x) => x.getKey() === key);\n\n/* method for registering items in container */\n/**\n * Method for registering items in container, optionally setting a lifespan for items\n * @param key for representing item in register, second use of the same key override previous item\n * @param item stored item, can be any type: value, type, function....\n * @param lifecycle setting type of life-span [value, singleton, transient] - value is default\n */\nconst register = (key: string, item: any, lifecycle?: string): void => {\n  if (!isVarName(key)) {\n    throw new IncorrectContainerKeyNameError(key);\n  }\n  const containerItems = takeContainerByKey(key);\n  if (containerItems.length === 0) {\n    const ci = containerItem.containerItemFactory(key, item, lifecycle);\n    containerRegister.push(ci);\n  } else {\n    containerItems[0].Item = item;\n  }\n};\n\n/** method for getting item from register\n * Method which returns item previously registered for passed key\n * @param key for representing item in register\n * @return { any } return stored item\n */\nconst take = (key: string): any => {\n  const containerItems = takeContainerByKey(key);\n  return containerItems.length === 0 ? null : containerItems[0].Item;\n};\n\n/** method for getting all the keys in container\n * @return array of keys\n */\nconst keys = (): string[] => containerRegister.map((x) => x.getKey());\n\nconst container = {\n  register,\n  take,\n  keys,\n};\n\nexport default container as IContainer;\n"
  },
  {
    "path": "packages/hadron-core/src/container/containerItem.ts",
    "content": "import container from './container';\nimport { IContainerItem } from './types';\nimport { Lifecycle } from './lifecycle';\nimport { getArgs } from '@brainhubeu/hadron-utils';\n\nexport class ContainerItem implements IContainerItem {\n  // tslint:disable-next-line:variable-name\n  constructor(protected key: string, protected item: any) {}\n\n  get Item(): any {\n    return this.item;\n  }\n  set Item(item: any) {\n    this.item = item;\n  }\n\n  public getKey() {\n    return this.key;\n  }\n  public getArgs(): string[] {\n    return getArgs(this.item);\n  }\n}\n\n// tslint:disable-next-line:max-classes-per-file\nclass ContainerItemSingleton extends ContainerItem {\n  // tslint:disable-next-line:variable-name\n  private _itemInstanse: any;\n\n  constructor(key: string, item: any) {\n    super(key, item);\n    this._itemInstanse = null;\n  }\n\n  set Item(item: any) {\n    this.item = item;\n  }\n  get Item(): any {\n    const parameters = this.getArgs();\n    if (parameters.length > 0) {\n      const parameterInstances = parameters.map((paramName) =>\n        container.take(paramName),\n      );\n      if (this._itemInstanse === null) {\n        try {\n          this._itemInstanse = new this.item(...parameterInstances);\n        } catch (error) {\n          throw new Error(`can not create an instance of ${this.key}`);\n        }\n      }\n      return this._itemInstanse;\n    }\n\n    if (this._itemInstanse === null) {\n      try {\n        this._itemInstanse = new this.item();\n      } catch (error) {\n        throw new Error(`can not create an instance of  ${this.key}`);\n      }\n    }\n    return this._itemInstanse;\n  }\n}\n// tslint:disable-next-line:max-classes-per-file\nclass ContainerItemTransient extends ContainerItem {\n  constructor(key: string, item: any) {\n    super(key, item);\n  }\n\n  set Item(item: any) {\n    this.item = item;\n  }\n  get Item(): any {\n    const parameters = this.getArgs();\n    if (parameters.length > 0) {\n      const parameterInstances = parameters.map((paramName) =>\n        container.take(paramName),\n      );\n      try {\n        return new this.item(...parameterInstances);\n      } catch (error) {\n        throw new Error(`can not create a new instance of  ${this.key}`);\n      }\n    } else {\n      try {\n        return new this.item();\n      } catch (error) {\n        throw new Error(`can not create a new instance of  ${this.key}`);\n      }\n    }\n  }\n}\n\nconst containerItemFactory = (\n  key: string,\n  item: any,\n  lifecycle?: string,\n): ContainerItem => {\n  switch (lifecycle) {\n    case Lifecycle.Singleton:\n      return new ContainerItemSingleton(key, item);\n    case Lifecycle.Transient:\n      return new ContainerItemTransient(key, item);\n    default:\n      return new ContainerItem(key, item);\n  }\n};\n\nexport default { containerItemFactory };\n"
  },
  {
    "path": "packages/hadron-core/src/container/lifecycle.ts",
    "content": "enum Lifecycle {\n  Transient = 'transient',\n  Singleton = 'singleton',\n  Value = 'value',\n}\n\nexport { Lifecycle };\n"
  },
  {
    "path": "packages/hadron-core/src/container/types.ts",
    "content": "interface IContainerItem {\n  Item(): any;\n  Item(key: string): void;\n  getKey(): string;\n  getArgs(): string[];\n}\n\ninterface IContainer {\n  take: (key: string) => any;\n  register: (key: string, value: any, lifecycle?: string) => any;\n  keys: () => string[];\n}\n\nexport { IContainerItem, IContainer };\n"
  },
  {
    "path": "packages/hadron-core/src/declarations.d.ts",
    "content": "declare module '@hadron/utils';\n"
  },
  {
    "path": "packages/hadron-core/src/errors/IncorrectContainerKeyNameError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class IncorrectContainerKeyNameError extends HadronErrorHandler {\n  constructor(key: string, err: Error = new Error()) {\n    super();\n    this.message = `The key name '${key}' is incorrect to register in container, should be a valid variable name.`;\n    this.name = 'IncorrectContainerKeyNameError';\n    this.stack = null;\n    this.error = err;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-core/src/errors/LoadingPackageError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class LoadingPackageError extends HadronErrorHandler {\n  constructor(err: Error) {\n    super();\n    this.message = `Problem with loading package`;\n    this.name = 'LoadingPackageError';\n    this.stack = null;\n    this.error = err;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-core/src/hadronCore.ts",
    "content": "import container from './container/container';\nimport { IContainer } from './container/types';\nimport { createLogger } from 'bunyan';\nconst hadronDefaultConfig = {};\n\nexport const prepareConfig = (\n  defaultConfig: object | Promise<object>,\n  config: object | Promise<object>,\n  logger: any,\n) => {\n  return Promise.all([defaultConfig, config])\n    .then(([resolvedDefaultConfig, resolvedConfig]) => ({\n      ...resolvedDefaultConfig,\n      ...resolvedConfig,\n    }))\n    .catch((err) => {\n      logger.error(`Config promise rejected: ${err}`);\n      return defaultConfig;\n    });\n};\n\nexport default (\n  server: any,\n  packages: any[] = [],\n  config: any = {},\n): Promise<IContainer> => {\n  container.register('server', server);\n\n  const logger = createLogger({ name: 'hadron-logger' });\n  container.register('hadronLogger', logger);\n\n  return prepareConfig(hadronDefaultConfig, config, logger).then(\n    (hadronConfig) => {\n      return Promise.all(\n        packages\n          .filter(({ register }) => !!register)\n          .map(({ register }) => register(container, hadronConfig)),\n      ).then(() => container);\n    },\n  );\n};\n"
  },
  {
    "path": "packages/hadron-core/src/helpers/__tests__/isVarName.ts",
    "content": "import { assert } from 'chai';\nimport isVarName from '../isVarName';\n\ndescribe('isVarName', () => {\n  it('when provided \"variable\" should return true', () => {\n    assert(isVarName('variable'));\n  });\n  it('when provided \"someLongVariableNameMayBeCorrect\" should return true', () => {\n    assert(isVarName('someLongVariableNameMayBeCorrect'));\n  });\n  it('when provided \"delete\" should return true', () => {\n    assert(isVarName('delete'));\n  });\n  it('when provided \"var\" should return true', () => {\n    assert(isVarName('var'));\n  });\n  it('when provided \"do\" should return true', () => {\n    assert(isVarName('do'));\n  });\n  it('when provided \"1\" should return false', () => {\n    assert(!isVarName('1'));\n  });\n  it('when provided \"1variable\" should return false', () => {\n    assert(!isVarName('1variable'));\n  });\n  it('when provided \"-v\" should return false', () => {\n    assert(!isVarName('-v'));\n  });\n  it('when provided \"variable-name\" should return false', () => {\n    assert(!isVarName('variable-name'));\n  });\n  it('when provided \"variable name\" should return false', () => {\n    assert(!isVarName('variable name'));\n  });\n});\n"
  },
  {
    "path": "packages/hadron-core/src/helpers/isVarName.ts",
    "content": "// tslint:disable:no-eval\nexport default function isVarName(str: string): boolean {\n  if (typeof str !== 'string') {\n    return false;\n  }\n\n  if (str.trim() !== str) {\n    return false;\n  }\n\n  if (!isNaN(parseInt(str[0], null))) {\n    return false;\n  }\n\n  try {\n    eval(`var temp = { ${str}: null }`);\n  } catch (e) {\n    return false;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "packages/hadron-core/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-demo/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-demo/README.md",
    "content": "# Demo App for Hadron framework\n\nTo start just run\n\n```bash\n  npm run start\n```\n\n<b>Requires TS-Node (for now)</b>\n"
  },
  {
    "path": "packages/hadron-demo/declarations.d.ts",
    "content": "declare module 'xmljson';\ndeclare module 'glob';\ndeclare module 'xml2js';\n\ndeclare module '*.json' {\n  const value: any;\n  // @ts-ignore\n  export default value;\n}\ndeclare module '*.js' {\n  const value: any;\n  // @ts-ignore\n  export default value;\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/Role.ts",
    "content": "import { IRole } from '@brainhubeu/hadron-auth';\nimport { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';\n\n@Entity()\nexport class Role implements IRole {\n  @PrimaryGeneratedColumn() public id: string | number;\n  @Column({ type: 'text' })\n  public name: string;\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/Team.ts",
    "content": "import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\nimport { User } from './User';\n\n@Entity()\nexport class Team {\n  @PrimaryGeneratedColumn() public id: number;\n\n  @Column({ type: 'text' })\n  public name: string;\n\n  @OneToMany((type) => User, (user) => user.team)\n  public users: User[];\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/User.ts",
    "content": "import {\n  Column,\n  Entity,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n  ManyToMany,\n  JoinTable,\n} from 'typeorm';\nimport { Team } from './Team';\nimport { IUser, IRole } from '@brainhubeu/hadron-auth';\nimport { Role } from './Role';\n\n@Entity()\nexport class User implements IUser {\n  @PrimaryGeneratedColumn() public id: number;\n\n  @Column({ type: 'text' })\n  public username: string;\n\n  @Column({ type: 'text' })\n  public passwordHash: string;\n\n  @ManyToOne((type) => Team, (team) => team.users)\n  public team: Team;\n\n  @ManyToMany((type) => Role, {\n    cascadeInsert: true,\n    cascadeUpdate: true,\n  })\n  @JoinTable({ name: 'user_role' })\n  public roles: IRole[];\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/validation/schemas.ts",
    "content": "import insertTeam = require('./team/insertTeam.json');\nimport updateTeam = require('./team/updateTeam.json');\nimport insertUser = require('./user/insertUser.json');\nimport updateUser = require('./user/updateUser.json');\n\nexport default {\n  insertTeam,\n  updateTeam,\n  insertUser,\n  updateUser,\n};\n"
  },
  {
    "path": "packages/hadron-demo/entity/validation/team/insertTeam.json",
    "content": "{\n    \"type\": \"object\",\n    \"properties\": {\n        \"teamName\": {\n            \"type\": \"string\"\n        }\n    },\n    \"required\": [\"teamName\"],\n    \"additionalProperties\": false\n}"
  },
  {
    "path": "packages/hadron-demo/entity/validation/team/updateTeam.json",
    "content": "{\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\n            \"type\": \"number\"\n        },\n        \"teamName\": {\n            \"type\": \"string\"\n        }\n    },\n    \"required\": [\"id\", \"teamName\"],\n    \"additionalProperties\": false\n}"
  },
  {
    "path": "packages/hadron-demo/entity/validation/user/insertUser.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"username\": {\n      \"type\": \"string\"\n    },\n    \"password\": {\n      \"type\": \"string\"\n    },\n    \"teamId\": {\n      \"type\": \"number\"\n    }\n  },\n  \"required\": [\"username\", \"password\", \"teamId\"],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/validation/user/updateUser.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"number\"\n    },\n    \"username\": {\n      \"type\": \"string\"\n    },\n    \"teamId\": {\n      \"type\": \"number\"\n    }\n  },\n  \"required\": [\"id\", \"username\", \"teamId\"],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "packages/hadron-demo/entity/validation/validate.ts",
    "content": "import validatorFactory from '../../../hadron-validation';\nimport schemas from './schemas';\n\nexport default validatorFactory(schemas);\n"
  },
  {
    "path": "packages/hadron-demo/event-emitter/case1/index.ts",
    "content": "import eventManagerProvider, { IEventsConfig } from '@brainhubeu/hadron-events';\nimport { EventEmitter } from 'events';\n\nconst emitter = new EventEmitter();\nconst config = {} as IEventsConfig;\n\nconst eventManager = eventManagerProvider(emitter, config);\n\nconst listeners = [\n  {\n    name: 'LISTENER',\n    event: 'testEvent', // event to listen to\n    handler: (callback: any, ...args: any[]) => {\n      const result = callback(...args);\n      return `${result}-changed`;\n    },\n  },\n];\n\neventManager.registerEvents(listeners);\n\nconst callback = () => 'testcase';\n\nconst newCallback = eventManager.emitEvent('testEvent', callback);\nnewCallback();\n"
  },
  {
    "path": "packages/hadron-demo/event-emitter/case2/index.ts",
    "content": "import eventManagerProvider, { IEventsConfig } from '@brainhubeu/hadron-events';\nimport { EventEmitter } from 'events';\n\nconst emitter = new EventEmitter();\nconst config = {} as IEventsConfig;\n\nconst eventManager = eventManagerProvider(emitter, config);\n\nconst listeners = [\n  {\n    name: 'LISTENER',\n    event: 'testEvent', // event to listen to\n    handler: () => 'test console log',\n  },\n];\n\neventManager.registerEvents(listeners);\n\nconst callback = () => 'testcase';\n\nconst newCallback = eventManager.emitEvent('testEvent', callback);\nnewCallback();\n"
  },
  {
    "path": "packages/hadron-demo/event-emitter/case3/index.ts",
    "content": "import eventManagerProvider, { IEventsConfig } from '@brainhubeu/hadron-events';\nimport { EventEmitter } from 'events';\n\nconst emitter = new EventEmitter();\nconst config = {} as IEventsConfig;\n\nconst eventManager = eventManagerProvider(emitter, config);\n\nconst listeners = [\n  {\n    name: 'LISTENER',\n    event: 'testEvent', // event to listen to\n    handler: (callback: any, ...args: any[]) => {\n      const time1 = Date.now();\n      callback(...args);\n      const time2 = Date.now();\n      return time2 - time1;\n    },\n  },\n];\n\neventManager.registerEvents(listeners);\n\nconst callback = () => 'testcase';\n\nconst newCallback = eventManager.emitEvent('testEvent', callback);\nnewCallback();\n"
  },
  {
    "path": "packages/hadron-demo/event-emitter/config.ts",
    "content": "import { IEventsConfig } from '@brainhubeu/hadron-events';\n\nconst emitterConfig: IEventsConfig = {\n  listeners: [\n    {\n      name: 'LISTENER-1',\n      event: 'handleTerminateApplicationEvent', // event to listen to\n      handler: (callback: any, ...args: any[]) => {\n        const cb = () => {\n          callback(...args);\n        };\n        return cb();\n      },\n    },\n\n    {\n      name: 'LISTENER-2',\n      event: 'handleInitializeApplicationEvent', // event to listen to\n      handler: () => {\n        // console.log('-----------app started-----------')\n      },\n    },\n  ],\n};\n\nexport default emitterConfig;\n"
  },
  {
    "path": "packages/hadron-demo/express-demo/index.ts",
    "content": "import { Container as container } from '@brainhubeu/hadron-core';\n\nconst getDate = () => {\n  const d = new Date();\n  return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`;\n};\n\nexport default {\n  routes: {\n    //\n    // Basic Hello World\n    //\n    helloWorldRoute: {\n      path: '/',\n      callback: () => 'Hello world',\n      methods: ['get'],\n    },\n\n    //\n    // Route containing single middleware\n    //\n    singleMiddleware: {\n      path: '/singleMiddleware',\n      callback: () => `Hey! See console`,\n      methods: ['get'],\n      middleware: [\n        (req: any, res: any, next: any) => {\n          // tslint:disable:no-console\n          console.log(`Hello, it's me, the very first middleware!`);\n          next();\n        },\n      ],\n    },\n\n    //\n    // Using multiple middlewares\n    //\n    multipleMiddlewares: {\n      path: '/multipleMiddlewares',\n      callback: () => `Hey! See console`,\n      methods: ['get'],\n      middleware: [\n        (req: any, res: any, next: any) => {\n          // tslint:disable:no-console\n          console.log(\n            `${getDate()}> First middleware, jump to next middleware in one second.`,\n          );\n          setTimeout(() => {\n            next();\n          }, 1000);\n        },\n        (req: any, res: any, next: any) => {\n          // tslint:disable:no-console\n          console.log(\n            `${getDate()}> Finally second middleware. One second passed i think !`,\n          );\n          next();\n        },\n      ],\n    },\n\n    //\n    // Load value registered in container\n    //\n    containerKey: {\n      path: '/getContainerValue',\n      methods: ['get'],\n      callback: (req: any, { customValue }: any) => customValue,\n    },\n\n    //\n    // Load custom value registered in container\n    //\n    customContainerKey: {\n      path: '/getContainerValue/:key',\n      methods: ['get'],\n      callback: (req: any, { key }: { key: string }) => container.take(key),\n    },\n\n    //\n    // Display URL parameter\n    //\n    routeWithParam: {\n      path: '/:param',\n      methods: ['get'],\n      callback: ({ params }: any) => `First route param: ${params.param}`,\n    },\n\n    //\n    // Display multiple URL parameters\n    //\n    routeWithMultipleParams: {\n      path: '/:param/:param2',\n      methods: ['get'],\n      callback: ({ params }: any) =>\n        `First param value: ${params.param}; Second param value: ${\n          params.param2\n        }`,\n    },\n\n    //\n    // Register container value under specific key\n    //\n    registerCustomValue: {\n      path: '/:key',\n      methods: ['post'],\n      callback: ({ params, body }: any) => {\n        container.register(params.key, body.value);\n        return `Value under key '${params.key}' is registered`;\n      },\n    },\n\n    //\n    // Clear value under specific key in container\n    //\n    deleteCustomValue: {\n      path: '/:key',\n      methods: ['delete'],\n      callback: ({ params }: any) => {\n        container.register(params.key, null);\n        return `Value under key '${params.key}' has been deleted`;\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "packages/hadron-demo/index.ts",
    "content": "import * as bodyParser from 'body-parser';\nimport * as express from 'express';\nimport hadron, { IContainer } from '@brainhubeu/hadron-core';\nimport * as hadronEvents from '@brainhubeu/hadron-events';\nimport * as hadronSerialization from '@brainhubeu/hadron-serialization';\nimport * as hadronExpress from '@brainhubeu/hadron-express';\nimport * as hadronLogger from '@brainhubeu/hadron-logger';\nimport * as hadronTypeOrm from '@brainhubeu/hadron-typeorm';\nimport * as hadronAuth from '@brainhubeu/hadron-auth';\nimport jsonProvider from '@brainhubeu/hadron-json-provider';\nimport expressConfig from './express-demo';\nimport typeormConfig from './typeorm-demo/index';\nimport emitterConfig from './event-emitter/config';\nimport serializationRoutes from './serialization/routing';\nimport { setupSerializer } from './serialization/serialization-demo';\nimport 'reflect-metadata';\nimport securedRoutes from './security/securedRoutesConfig';\n\nconst port = process.env.PORT || 8080;\nconst expressApp = express();\nexpressApp.use(bodyParser.json());\n\njsonProvider([`${__dirname}/routing/*`], ['config.js']).then((routes: any) => {\n  const config = {\n    securedRoutes,\n    ...typeormConfig,\n    ...hadronLogger,\n    events: emitterConfig,\n    routes: {\n      ...serializationRoutes,\n      ...routes,\n      ...expressConfig.routes,\n    },\n  };\n\n  hadron(\n    expressApp,\n    [\n      hadronAuth,\n      hadronEvents,\n      hadronSerialization,\n      hadronTypeOrm,\n      hadronExpress,\n    ],\n    config,\n  )\n    .then((container: IContainer) => {\n      expressApp.use((req, res, next) =>\n        res.status(404).json('Endpoint not found.'),\n      );\n      container.register('customValue', 'From Brainhub with ❤️');\n\n      setupSerializer();\n      expressApp.listen(port);\n    })\n    .catch(console.log);\n\n  return;\n});\n"
  },
  {
    "path": "packages/hadron-demo/logger/adapters/winstonAdapter.ts",
    "content": "import * as winston from 'winston';\nimport { ILogger } from '@brainhubeu/hadron-logger';\n\nexport default (config: any): ILogger => {\n  winston.loggers.add(config.name, config);\n  const logger = winston.loggers.get(config.name);\n\n  return {\n    log: (message: string) => {\n      logger.info(message);\n    },\n    debug: (message: string) => {\n      logger.debug(message);\n    },\n    warn: (message: string) => {\n      logger.warn(message);\n    },\n    error: (message: string) => {\n      logger.error(message);\n    },\n  };\n};\n"
  },
  {
    "path": "packages/hadron-demo/logger/index.ts",
    "content": "export default {\n  logger: [\n    {\n      type: 'bunyan',\n      name: 'first logger',\n    },\n    {\n      type: 'winston',\n      name: 'second',\n    },\n    {\n      name: 'third ',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/hadron-demo/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-demo\",\n  \"version\": \"1.1.4\",\n  \"description\": \"Hadron demo example app\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"ts-node index.ts\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-demo\"\n  ],\n  \"dependencies\": {\n    \"@brainhubeu/hadron-auth\": \"^0.0.2\",\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"@brainhubeu/hadron-events\": \"^1.0.1\",\n    \"@brainhubeu/hadron-express\": \"^2.0.0\",\n    \"@brainhubeu/hadron-json-provider\": \"^1.0.0\",\n    \"@brainhubeu/hadron-logger\": \"^1.0.1\",\n    \"@brainhubeu/hadron-serialization\": \"^1.0.0\",\n    \"@brainhubeu/hadron-typeorm\": \"^1.0.3\",\n    \"@brainhubeu/hadron-utils\": \"^1.0.0\",\n    \"@brainhubeu/hadron-validation\": \"^1.0.0\",\n    \"bcrypt\": \"^2.0.1\",\n    \"body-parser\": \"1.18.2\",\n    \"cors\": \"2.8.4\",\n    \"dotenv\": \"4.0.0\",\n    \"express\": \"4.16.2\",\n    \"jsonwebtoken\": \"^8.2.2\",\n    \"multer\": \"1.3.0\",\n    \"mysql\": \"2.15.0\",\n    \"reflect-metadata\": \"^0.1.12\",\n    \"typeorm\": \"0.1.18\"\n  },\n  \"devDependencies\": {\n    \"@types/body-parser\": \"1.16.8\",\n    \"@types/cors\": \"2.8.3\",\n    \"@types/dotenv\": \"4.0.2\",\n    \"@types/express\": \"4.11.1\",\n    \"@types/multer\": \"1.3.6\",\n    \"@types/node\": \"9.6.0\"\n  },\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/README.md",
    "content": "# Performance Tests\n\n## Testing toolkit\n\nArtillery - [Artillery website](https://artillery.io/)\n\n## Basic commmands\n\n* duration: x - phase will last for x seconds\n* arrivalRate: x - x new virtual users will arrive every second in phase\n\n## Example\n\ninsertUser.yml\n\n```\n    config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n    - loop:\n        - post:\n            url: '/insertUser'\n            json:\n              userName: 'Test'\n              teamId: 1\n      count: 3\n```\n\n## How to run\n\n* First we need to install Artillery with npm\n\n```\n    npm install -g artillery\n```\n\n* Now we can do a quick test:\n\n```\n    artillery quick --count 10 -n 20 http://localhost:8080/user\n```\n\nWhere: count - amount of virtual users, n - each virtual user will send 20 GET requests.  \nOf course to make it work on localhost:8080/\\* **_we need to run hadron-demo with sql_**\n\n* Artillery also provides test scripts as in example section. We can run test script with command:\n\n```\n    artillery run filename.yml\n```\n\n## Output\n\n```\nAll virtual users finished\nSummary report @ 15:10:41(+0200) 2018-04-05\n  Scenarios launched:  609\n  Scenarios completed: 609\n  Requests completed:  1827\n  RPS sent: 29.64\n  Request latency:\n    min: 4.2\n    max: 4905.6\n    median: 184.7\n    p95: 2472.6\n    p99: 4358.4\n  Scenario counts:\n    Inserting, updating, deleting and searching teams: 609 (100%)\n  Codes:\n    200: 609\n    201: 1218\n```\n\nWhere:\n\n* **_Scenarios launched_** - number of virtual users created\n* **_Scenarios completed_** - number of virtual users completed their scenarios\n* **_Request completed_** - number of HTTP requests or responses sent\n* **_RPS sent_** - average number of requests per second\n* **_Request latency_** - are in milliseconds. (a request latency p99 value of 500ms means that 99 out of 100 requests took 500ms or less to complete)\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/teamService/getTeams.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n      - get:\n          url: '/team'\n          "
  },
  {
    "path": "packages/hadron-demo/performance-tests/teamService/insertTeam.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n    - loop:\n        - post:\n            url: '/insertTeam'\n            json:\n              teamName: 'Test Team'\n      count: 3\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/teamService/team.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n    - duration: 20\n      arrivalRate: 10\n      rampTo: 30\n    - duration: 30\n      arrivalRate: 5\nscenarios:\n  - name: 'Inserting, updating, deleting and searching teams'\n    flow:\n      - post:\n          url: '/insertTeam'\n          json:\n            teamName: 'Team Test'\n      - put:\n          url: '/updateTeam'\n          json:\n            id: 2\n            teamName: 'Team 2'\n      - get:\n          url: '/team'\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/teamService/updateTeam.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n    - loop:\n        - put:\n            url: '/updateTeam'\n            json:\n              id: 1\n              teamName: 'Updated team!'\n      count: 3\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/userService/getUsers.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n      - get:\n          url: '/user'\n          "
  },
  {
    "path": "packages/hadron-demo/performance-tests/userService/insertUser.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n    - loop:\n        - post:\n            url: '/insertUser'\n            json:\n              userName: 'Test'\n              teamId: 1\n      count: 3\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/userService/updateUser.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n  defaults:\nscenarios:\n  - flow:\n    - loop:\n        - put:\n            url: '/updateUser'\n            json:\n              id: 2\n              userName: 'Test'\n              teamId: 1\n      count: 3\n"
  },
  {
    "path": "packages/hadron-demo/performance-tests/userService/user.yml",
    "content": "config:\n  target: 'http://localhost:8080'\n  phases:\n    - duration: 10\n      arrivalRate: 5\n    - duration: 20\n      arrivalRate: 10\n      rampTo: 30\n    - duration: 30\n      arrivalRate: 5\nscenarios:\n  - name: 'Inserting, updating, deleting and searching users'\n    flow:\n      - post:\n          url: '/insertUser'\n          json:\n            userName: 'Test'\n            teamId: 1\n      - put:\n          url: '/updateUser'\n          json:\n            id: 2\n            userName: 'BB'\n            teamId: 1\n      - delete:\n          url: '/deleteUser/3'\n      - get:\n          url: '/user'\n"
  },
  {
    "path": "packages/hadron-demo/routing/home.config.js",
    "content": "const helloWorldCallback = () => 'Hello world';\nconst versionCallback = () => `Version: ${process.env.VERSION || '0.0.1'}`;\nconst login = require('../security/loginRoute').default;\n\nconst homeConfig = () => {\n  return {\n    helloWorldRoute: {\n      callback: helloWorldCallback,\n      methods: ['GET'],\n      path: '/',\n    },\n    versionRoute: {\n      callback: versionCallback,\n      methods: ['get'],\n      path: '/version',\n    },\n    login: {\n      callback: login,\n      methods: ['POST'],\n      path: '/login',\n    },\n  };\n};\n\nmodule.exports = homeConfig;\n"
  },
  {
    "path": "packages/hadron-demo/routing/nested-routes.config.js",
    "content": "const testMiddleware = (req, res, next) => {\n  res.locals.injected = 'I was injected here!';\n  next();\n};\n\nconst teamRoutsConfig = () => {\n  return {\n    nestedRoutes: {\n      callback: (req, container, locals) => ({\n        body: { response: 'Hello There!', locals },\n      }),\n      path: '/test/',\n      methods: ['GET'],\n      middleware: [testMiddleware],\n      routes: {\n        route1: {\n          callback: (req, container, locals) => ({\n            body: { response: 'General Kenobi', locals },\n          }),\n          methods: ['GET'],\n          path: '/route1/',\n        },\n        deepRoute1: {\n          callback: (req, container, locals) => ({\n            body: { response: 'You are a bold one!', locals },\n          }),\n          methods: ['POST'],\n          $middleware: [],\n          path: '/route2/',\n        },\n        route3: {\n          callback: (req, container, locals) => ({\n            body: { response: 'Kill him...', locals },\n          }),\n          methods: ['GET'],\n          middleware: [\n            (req, res, next) => {\n              res.locals.additionalInjection = 'Some tasty addition';\n              next();\n            },\n          ],\n          $path: '/route3/',\n          routes: {\n            deepRoute1: {\n              path: '/deepRoute/',\n              callback: (req, container, locals) => ({\n                body: { response: 'Kill him...', locals },\n              }),\n            },\n          },\n        },\n      },\n    },\n  };\n};\n\nmodule.exports = teamRoutsConfig;\n"
  },
  {
    "path": "packages/hadron-demo/routing/team.config.js",
    "content": "const teamService = require('../services/teamService');\n\nconst teamRoutsConfig = () => {\n  return {\n    getTeams: {\n      callback: teamService.getAllTeams,\n      methods: ['GET'],\n      path: '/team/',\n    },\n    getTeamById: {\n      callback: teamService.getTeamById,\n      methods: ['GET'],\n      path: '/team/:id',\n    },\n    insertTeam: {\n      callback: teamService.insertTeam,\n      methods: ['POST'],\n      path: '/team',\n    },\n    updateTeam: {\n      callback: teamService.updateTeam,\n      methods: ['PUT'],\n      path: '/team',\n    },\n    deleteTeam: {\n      callback: teamService.deleteTeam,\n      methods: ['DELETE'],\n      path: '/team/:id',\n    },\n  };\n};\n\nmodule.exports = teamRoutsConfig;\n"
  },
  {
    "path": "packages/hadron-demo/routing/user.config.js",
    "content": "const userService = require('../services/userService');\n\nconst userRoutsConfig = () => {\n  return {\n    getAllUsers: {\n      callback: userService.getAllUsers,\n      methods: ['GET'],\n      path: '/user/',\n    },\n    getUserById: {\n      callback: userService.getUserById,\n      methods: ['GET'],\n      path: '/user/:id',\n    },\n    insertUser: {\n      callback: userService.insertUser,\n      methods: ['POST'],\n      path: '/user/',\n    },\n    updateUser: {\n      callback: userService.updateUser,\n      methods: ['PUT'],\n      path: '/user/',\n    },\n    deleteUser: {\n      callback: userService.deleteUser,\n      methods: ['DELETE'],\n      path: '/user/:id',\n    },\n  };\n};\n\nmodule.exports = userRoutsConfig;\n"
  },
  {
    "path": "packages/hadron-demo/security/loginRoute.ts",
    "content": "import * as jwt from 'jsonwebtoken';\nimport { bcrypt } from '@brainhubeu/hadron-auth';\n\nconst secret = process.env.JWT_SECRET || 'H4DR0N_S3CUR17Y';\n\nconst unauthorized = {\n  status: 403,\n  body: {\n    error: {\n      message: 'Unauthorized',\n    },\n  },\n};\n\nconst login = async (req: any, { userRepository }) => {\n  try {\n    const user = await userRepository.findOne({\n      where: { username: req.body.username },\n    });\n\n    if (!user) {\n      return unauthorized;\n    }\n\n    const validPassword = await bcrypt.compare(\n      req.body.password,\n      user.passwordHash,\n    );\n\n    if (validPassword) {\n      const token = jwt.sign(\n        {\n          id: user.id,\n          username: user.username,\n        },\n        secret,\n        {\n          expiresIn: '2h',\n        },\n      );\n\n      return {\n        status: 200,\n        body: {\n          token,\n        },\n      };\n    }\n    return unauthorized;\n  } catch (error) {\n    return unauthorized;\n  }\n};\n\nexport default login;\n"
  },
  {
    "path": "packages/hadron-demo/security/securedRoutesConfig.ts",
    "content": "const securedRoutesConfig = [\n  {\n    path: '/team/*',\n    roles: [['Admin', 'User'], 'Manager'],\n  },\n  {\n    path: '/user/*',\n    methods: ['GET'],\n    roles: ['NotExists', 'User', 'Admin'],\n  },\n  {\n    path: '/user/*',\n    methods: ['POST', 'PUT', 'DELETE'],\n    roles: 'Admin',\n  },\n];\n\nexport default securedRoutesConfig;\n"
  },
  {
    "path": "packages/hadron-demo/serialization/routing/index.ts",
    "content": "import unicornsRoutes from './unicorns';\nimport princessesRoutes from './princesses';\n\nexport default {\n  ...unicornsRoutes,\n  ...princessesRoutes,\n};\n"
  },
  {
    "path": "packages/hadron-demo/serialization/routing/princesses.ts",
    "content": "import { Container } from '@brainhubeu/hadron-core';\nimport { princesses } from '../unicorns-and-princesses';\nimport { ISerializer } from '@brainhubeu/hadron-serialization';\n\nContainer.register('princesses', princesses);\n\nexport default {\n  getPrincess: {\n    path: '/princesses/:name',\n    callback: ({ params }: any, { princesses }: any) => {\n      return {\n        body: princesses[params.name],\n      };\n    },\n    methods: ['get'],\n  },\n  getPrincessWithRole: {\n    path: '/princesses/:role/:name',\n    callback: ({ params }: any, { princesses, serializer }: any) => {\n      return {\n        body: serializer.serialize(\n          princesses[params.name],\n          [params.role],\n          'Princess',\n        ),\n      };\n    },\n    methods: ['get'],\n  },\n  getPrincessWithRoleAndSerializer: {\n    path: '/princesses/:role/:name',\n    callback: ({ params }: any, { princesses, princessSerializer }: any) => {\n      return {\n        body: princessSerializer(princesses[params.name], [params.role]),\n      };\n    },\n    methods: ['get'],\n  },\n};\n"
  },
  {
    "path": "packages/hadron-demo/serialization/routing/unicorns.ts",
    "content": "import { Container } from '@brainhubeu/hadron-core';\nimport { unicorns } from '../unicorns-and-princesses';\nimport { ISerializer } from '@brainhubeu/hadron-serialization';\n\nContainer.register('unicorns', unicorns);\n\nexport default {\n  getUnicorn: {\n    path: '/unicorns/:name',\n    callback: ({ params }: any, { unicorns }: any) => {\n      return { body: unicorns[params.name] };\n    },\n    methods: ['get'],\n  },\n  getUnicornWithRole: {\n    path: '/unicorns/:role/:name',\n    callback: ({ params }: any, { serializer, unicorns }: any) => {\n      return {\n        body: serializer.serialize(\n          unicorns[params.name],\n          [params.role],\n          'Unicorn',\n        ),\n      };\n    },\n    methods: ['get'],\n  },\n  getUnicornWithRoleAndSerializer: {\n    path: '/unicorns/:role/:name',\n    callback: ({ params }: any, { unicorns, unicornSerializer }: any) => {\n      return {\n        body: unicornSerializer(unicorns[params.name], [params.role]),\n      };\n    },\n    methods: ['get'],\n  },\n};\n"
  },
  {
    "path": "packages/hadron-demo/serialization/schemas/princess.json",
    "content": "{\n    \"name\": \"Princess\",\n    \"properties\": [\n        { \"name\": \"name\", \"type\": \"string\" },\n        { \"name\": \"address\", \"type\": \"string\", \"groups\": [\"admin\"] },\n        { \"name\": \"money\", \"type\": \"number\", \"parsers\": [\"currency\"], \"groups\": [\"admin\"]},\n        {\n            \"name\": \"friends\",\n            \"type\": \"array\",\n            \"properties\": [\n                { \"name\": \"name\", \"type\": \"string\" },\n                { \"name\": \"profession\", \"type\": \"string\", \"groups\": [\"admin\"] },\n                { \"name\": \"salary\", \"type\": \"number\", \"parsers\": [\"currency\"] }\n            ]\n        }\n    ]\n}\n"
  },
  {
    "path": "packages/hadron-demo/serialization/schemas/unicorn.json",
    "content": "{\n    \"name\": \"Unicorn\",\n    \"properties\": [\n        { \"name\": \"name\", \"type\": \"string\" },\n        { \"name\": \"hornLength\", \"type\": \"number\", \"groups\": [\"expert\", \"admin\", \"buyer\"] },\n        {\n            \"name\": \"magicPower\",\n            \"type\": \"object\",\n            \"groups\": [\"expert\", \"admin\", \"buyer\"],\n            \"properties\" : [\n                { \"name\": \"name\", \"type\": \"string\" },\n                { \"name\": \"power\", \"type\": \"number\", \"serializationName\": \"powerLevel\" },\n                { \"name\": \"magicSchool\", \"type\": \"string\", \"groups\": [\"expert\"] }\n            ]\n        },\n        { \"name\": \"price\", \"type\": \"number\", \"parsers\": [\"currency\"], \"groups\": [\"buyer\", \"admin\"]}\n    ]\n}\n"
  },
  {
    "path": "packages/hadron-demo/serialization/serialization-demo.ts",
    "content": "import { Container } from '@brainhubeu/hadron-core';\nimport {\n  schemaProvider,\n  CONTAINER_NAME,\n  ISerializer,\n} from '@brainhubeu/hadron-serialization';\nimport { resolve } from 'path';\n\nconst paths = [resolve(__dirname, 'schemas/*')];\n\nexport const setupSerializer = () =>\n  schemaProvider(paths).then((schemas: any) => {\n    const serializer: ISerializer = Container.take(CONTAINER_NAME);\n    schemas.forEach(serializer.addSchema);\n    serializer.addParser((value: any) => `${value}$`, 'currency');\n  });\n\nexport const serializeUnicorn = (unicornData: any, groups: string[] = []) => {\n  const serializer = Container.take(CONTAINER_NAME) as ISerializer;\n  return serializer.serialize(unicornData, groups, 'Unicorn');\n};\n\nContainer.register('unicornSerializer', serializeUnicorn);\n\nexport const serializePrincess = (unicornData: any, groups: string[] = []) => {\n  const serializer = Container.take(CONTAINER_NAME) as ISerializer;\n  return serializer.serialize(unicornData, groups, 'Princess');\n};\n\nContainer.register('princessSerializer', serializePrincess);\n"
  },
  {
    "path": "packages/hadron-demo/serialization/unicorns-and-princesses.ts",
    "content": "export const unicorns = {\n  arthur: {\n    hornLength: '20',\n    id: '10002',\n    magicPower: {\n      magicSchool: 'Fake',\n      name: 'Power of Truth',\n      power: '12',\n      usability: '0',\n    },\n    name: 'RainbowHoof',\n    price: '2100',\n    secretName: 'RainbowFart',\n  },\n  cssdash: {\n    hornLength: '13',\n    id: 'd4sh',\n    magicPower: {\n      magicSchool: 'CSS',\n      name: 'Power of Vertically Align Things',\n      power: '8',\n      usability: '100',\n    },\n    name: 'Css Dash',\n    price: '10000',\n    psychologyProfile: 'Suicide Thoughts',\n  },\n};\n\nexport class Princess {\n  public address: any = null;\n  public friends: any = null;\n  public id: any = null;\n  public money: any = null;\n  public name: any = null;\n\n  constructor({ address, friends, id, money, name }: any) {\n    this.address = address;\n    this.friends = friends;\n    this.id = id;\n    this.money = money;\n    this.name = name;\n  }\n}\n\nexport const princesses = {\n  jasmine: new Princess({\n    address: 'Górnych Wałów 26/5',\n    friends: [\n      { name: 'Francesca', salary: '5120', profession: 'Cooker', id: '123' },\n      { name: 'Marina', salary: '2010', profession: 'Gardener' },\n      { name: 'Robin', salary: '0', profession: 'Crime Fighter' },\n    ],\n    id: '10002',\n    money: '21000',\n    name: 'Jasmine',\n  }),\n  veronica: new Princess({\n    address: 'Red Lanterns 66/6',\n    friends: [\n      {\n        name: 'Hilary',\n        salary: '6000',\n        profession: 'Not President',\n        id: '123',\n      },\n      {\n        name: 'Andrzej L',\n        salary: '3678.23',\n        profession: 'Farmer',\n        lpr: false,\n      },\n    ],\n    id: 'RT123',\n    money: '12000',\n    name: 'Veronic',\n  }),\n  jozin: new Princess({\n    address: 'Bazin',\n    friends: [],\n    id: '222',\n    money: 0,\n    name: 'Jozin',\n  }),\n};\n"
  },
  {
    "path": "packages/hadron-demo/services/teamService.ts",
    "content": "import { Team } from '../entity/Team';\nimport { User } from '../entity/User';\nimport { Repository } from 'typeorm';\nimport validate from '../entity/validation/validate';\n\nclass TeamDto {\n  constructor(public id: number, public name: string, public amount: number) {}\n}\n\nconst getAllTeams = async (req, { teamRepository }) => {\n  const teams = await teamRepository.find({ relations: ['users'] });\n\n  return {\n    body: teams.map(\n      (team) => new TeamDto(team.id, team.name, team.users.length),\n    ),\n  };\n};\n\nconst getTeamById = async ({ params }, { teamRepository }) => {\n  return {\n    body: await teamRepository.findOneById(params.id),\n  };\n};\n\nconst updateTeam = async ({ body }, { teamRepository }) => {\n  try {\n    await validate('updateTeam', body);\n\n    const team = teamRepository.findOneById(body.id);\n    team.name = body.teamName;\n\n    await teamRepository.save(team);\n\n    return {\n      body: { message: `team id: ${body.id} has new name ${body.teamName}` },\n    };\n  } catch (error) {\n    return {\n      status: 400,\n      body: { error: error.message },\n    };\n  }\n};\n\nconst insertTeam = async ({ body }, { teamRepository }) => {\n  try {\n    await validate('insertTeam', body);\n    await teamRepository.insert({ name: body.teamName });\n\n    const amount = await teamRepository.count();\n\n    return {\n      status: 201,\n      body: { message: `total amount of teams: ${amount}` },\n    };\n  } catch (error) {\n    return {\n      status: 400,\n      body: { error: error.message },\n    };\n  }\n};\n\nconst deleteTeam = async (\n  { params }: any,\n  { teamRepository, userRepository }: any,\n) => {\n  const team = await teamRepository.findOneById(params.id, {\n    relations: ['users'],\n  });\n\n  await userRepository.removeByIds(team.users.map((user) => user.id));\n\n  return {\n    body: await teamRepository.removeById(params.id),\n  };\n};\n\nexport { getAllTeams, getTeamById, updateTeam, insertTeam, deleteTeam };\n"
  },
  {
    "path": "packages/hadron-demo/services/userService.ts",
    "content": "import { User } from '../entity/User';\nimport validate from '../entity/validation/validate';\nimport { Container } from '@brainhubeu/hadron-core';\nimport { bcrypt } from '@brainhubeu/hadron-auth';\nimport { Role } from '../entity/Role';\n\nclass UserDto {\n  constructor(\n    public id: number,\n    public username: string,\n    public teamName: string,\n    public roles: Role[],\n  ) {}\n}\n\nconst getAllUsers = async (req, { userRepository }) => {\n  const users = await userRepository.find({ relations: ['team', 'roles'] });\n\n  return {\n    body: users.map(\n      (user: User) =>\n        new UserDto(user.id, user.username, user.team.name, user.roles),\n    ),\n  };\n};\n\nconst getUserById = async ({ params }, { userRepository }) => {\n  return {\n    body: await userRepository.findOneById(params.id),\n  };\n};\n\nconst insertUser = async (\n  req,\n  { teamRepository, userRepository, roleRepository },\n) => {\n  try {\n    await validate('insertUser', req.body);\n\n    const existingUser = await userRepository.findOne({\n      username: req.body.username,\n    });\n\n    if (existingUser) {\n      throw new Error(`User: ${existingUser.username} already exists.`);\n    }\n\n    const team = await teamRepository.findOneById(req.body.teamId);\n    const userRole = await roleRepository.findOne({ name: 'User' });\n    const password = await bcrypt.hash(req.body.password);\n\n    const user = new User();\n    user.username = req.body.username;\n    user.passwordHash = password;\n    user.team = team;\n    user.roles = [userRole];\n\n    await userRepository.insert(user);\n\n    const amount = await userRepository.count();\n\n    return {\n      status: 201,\n      body: { message: `Amount of users: ${amount}` },\n    };\n  } catch (error) {\n    return {\n      status: 400,\n      body: { error: error.message },\n    };\n  }\n};\n\nconst updateUser = async ({ body }, { userRepository }) => {\n  try {\n    await validate('updateUser', body);\n\n    const user = await userRepository.findOneById(body.id);\n    user.username = body.username;\n\n    await userRepository.save(user);\n\n    return {\n      body: { message: `user id: ${body.id} has new name: ${body.username}` },\n    };\n  } catch (error) {\n    return {\n      status: 400,\n      body: { error: error.message },\n    };\n  }\n};\n\nconst deleteUser = async ({ params }, { userRepository }) => {\n  return {\n    body: await userRepository.removeById(params.id),\n  };\n};\n\nexport {\n  UserDto,\n  getAllUsers,\n  getUserById,\n  insertUser,\n  updateUser,\n  deleteUser,\n};\n"
  },
  {
    "path": "packages/hadron-demo/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-demo/typeorm-demo/index.ts",
    "content": "import { ConnectionOptions } from 'typeorm';\nimport { User } from '../entity/User';\nimport { Team } from '../entity/Team';\nimport { Role } from '../entity/Role';\n\nconst connection: ConnectionOptions = {\n  name: 'mysql-connection',\n  type: 'mysql',\n  host: 'localhost',\n  port: 3306,\n  username: 'root',\n  password: 'my-secret-pw',\n  database: 'test',\n  entities: [User, Team, Role],\n  synchronize: true,\n};\n\nexport default {\n  connection,\n  entities: [User, Team, Role],\n};\n"
  },
  {
    "path": "packages/hadron-error-handler/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-error-handler/README.md",
    "content": "# Default Error for Hadron\n\n<b>(Currently there is nothing to see here)</b>\n"
  },
  {
    "path": "packages/hadron-error-handler/index.ts",
    "content": "import HadronError from './src/errorHandler';\n\nexport { HadronError as default };\n"
  },
  {
    "path": "packages/hadron-error-handler/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-error-handler\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Error handler for hadron\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"keywords\": [\n    \"error\",\n    \"hadron\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-error-handler/src/errorHandler.ts",
    "content": "class HadronError extends Error {\n  public error?: Error;\n  constructor(message: string = 'Hadron unhandled error') {\n    super(message);\n    this.stack = new Error().stack;\n  }\n}\n\nexport default HadronError;\n"
  },
  {
    "path": "packages/hadron-error-handler/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-events/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-events/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-events --save\n```\n\n[More info about installation](/core/#installation)\n\n## Overview\n\nEvent Manager is a tool which allows manipulating Hadron's default behavior without the need to change the code base. It can be achieved via custom listeners defined by the developer. There are a bunch of extension points spread all over the hadron framework where listeners can be hooked up.\n\n## Initializing\n\nPass package as an argument for hadron bootstrapping function:\n\n```javascript\nconst hadronEvents = require('@brainhubeu/hadron-events');\n// ... importing and initializing other components\n\nhadron(expressApp, [hadronEvents], config).then(() => {\n  console.log('Hadron with eventManager initialized');\n});\n```\n\nAfter initialization you can retrieve event manager from DI container - it is registered under the key `eventManager`.\n\n## Event Manager methods\n\n### Registering listeners for events\n\n```javascript\neventManager.registerEvents(listeners);\n```\n\n* `listeners` - an array of objects which have to follow convention showed below:\n\n```javascript\n{\n  name: 'string',  // listener name\n  event: 'string', // event to register to\n  handler: 'function' // function to handle the event\n}\n```\n\nExample:\n\n```javascript\nconst config = {\n  events: {\n    listeners: [\n      {\n        name: 'Listener1',\n        event: 'createRoutesEvent',\n        handler: (callback, ...args) => {\n          const myCustomCallback = () => {\n            console.log(\"Hey! I've changed the original hadron function!\");\n            return callback(...args);\n          };\n          return myCustomCallback();\n        },\n      },\n      {\n        name: 'Listener2',\n        event: 'myCustomEvent',\n        handler: (callback, ...args) => {\n          const myCustomCallback = () => {\n            console.log('My custom event!');\n            return callback(...args);\n          };\n          return myCustomCallback();\n        },\n      },\n    ],\n  },\n};\n\nhadron(app, [hadronEvents], config).then((container) => {\n  container.take('eventManager').emitEvent('myCustomEvent'); // \"My custom event!\"\n});\n```\n\n### Emitting events\n\n```javascript\neventEmitter.emitEvent(eventName);\n```\n\nCalls all listeners handlers registered for the event with event name passed to it.\n\n* `eventName` - name of the event which will be fired\n\n## Listeners\n\nYou can create your listeners in the main config file.\n\nAs a first argument listener's handler method will receive a callback function originally called by hadron, so you can change/override it however you want and then return a call of newly created function or a call of existing callback if you don't want to change it.\n\nTo be able to receive callback mentioned above, the first argument should be named exactly `callback`, otherwise, you will not receive the callback.\n\nYou can also, define your listener's handler without `callback` argument or even without any arguments, which is also a valid way to create listeners, you just won't be able to access the callback.\n\nThe second argument of listeners handler method is `...args`, which can be used as arguments for the callback function.\n\nAn example of a listener:\n\n```javascript\n{\n  name: 'Listener',\n  event: 'createRoutesEvent',\n  handler: (callback, ...args) => {\n    const myCustomCallback = () => {\n      console.log(\"Hey! I've changed the original hadron function!\");\n      return callback(...args);\n    }\n    return myCustomCallback();\n  }\n}\n```\n\n## Extension points in hadron\n\nAs said before, there are a couple of extension points in the hadron framework to which you can hook up your listeners.\nThe extension depends from packages that You are using and are listed below:\n\n--- hadron-express\n\n`HANDLE_REQUEST_CALLBACK_EVENT`\n\nEvent fires, before route callback function is called, passes route callback to the listener.\n\nExample:\n\n```javascript\nconst ExpressEvent = require('@brainhubeu/hadron-express').Event;\nconst listeners = [\n  {\n    name: 'Listener',\n    event: ExpressEvent.HANDLE_REQUEST_CALLBACK_EVENT, // or simply event: 'HANDLE_REQUEST_CALLBACK_EVENT'\n    handler: (callback, ...args) => {\n      console.log('Request Handled!');\n      callback(...args);\n    },\n  },\n];\n```\n\n---\n\n`HANDLE_TERMINATE_APPLICATION_EVENT`\n\nEvent fires when the application is terminated with <kbd>CTRL</kbd> + <kbd>C</kbd>, passes default hadron callback to the listener.\n\n```javascript\nconst Event = require('@brainhubeu/hadron-events').Event;\nconst listeners = [\n  {\n    name: 'Listener',\n    event: Event.HANDLE_TERMINATE_APPLICATION_EVENT, // or simply event: 'HANDLE_TERMINATE_APPLICATION_EVENT'\n    handler: () => {\n      console.log('Application is going to close');\n    },\n  },\n];\n```\n"
  },
  {
    "path": "packages/hadron-events/index.ts",
    "content": "import { EventEmitter } from 'events';\nimport { Lifecycle, IContainer } from '@brainhubeu/hadron-core';\n\nimport eventManagerProvider from './src/eventManagerProvider';\nimport { IHadronEventsConfig } from './src/types';\n\nimport registerProcessEvents from './src/registerProcessEvents';\n\nexport * from './src/types';\nexport * from './src/constants';\nexport default eventManagerProvider;\n\nexport const register = (\n  container: IContainer,\n  config: IHadronEventsConfig,\n) => {\n  if (container.take('eventEmitter') === null) {\n    container.register('eventEmitter', EventEmitter, Lifecycle.Singleton);\n  }\n  const eventManager = eventManagerProvider(\n    container.take('eventEmitter'),\n    config.events,\n  );\n  eventManager.registerEvents(config.events.listeners);\n  container.register('eventManager', eventManager);\n  registerProcessEvents(eventManager);\n};\n"
  },
  {
    "path": "packages/hadron-events/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-events\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Hadron event emitter module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-events\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"@brainhubeu/hadron-utils\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/events\": \"1.2.0\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-events/src/__tests__/eventManagerProvider.ts",
    "content": "import { expect } from 'chai';\nimport { EventEmitter } from 'events';\nimport * as sinon from 'sinon';\nimport { IEventListener, IEventsConfig } from '../types';\nimport eventManagerProvider from '../eventManagerProvider';\n\ndescribe('events registration', () => {\n  let emitter: EventEmitter = null;\n\n  beforeEach(() => {\n    emitter = new EventEmitter();\n  });\n\n  afterEach(() => {\n    emitter = null;\n  });\n\n  it('throws an error if eventName is either null or empty string', () => {\n    const listeners: IEventListener[] = [\n      {\n        name: 'my-listener-1',\n        event: '', // event to listen to\n        handler: (callback, ...args) => {\n          return callback(...args);\n        },\n      },\n      {\n        name: 'my-listener-2',\n        event: 'someEvent',\n        handler: (callback, ...args) => {\n          return callback(...args);\n        },\n      },\n      {\n        name: 'my-listener-3',\n        event: 'someEvent', // event to listen to\n        handler: (callback, ...args) => {\n          return callback(...args);\n        },\n      },\n    ];\n\n    const config = {} as IEventsConfig;\n    const eventManager = eventManagerProvider(emitter, config);\n    expect(() => eventManager.registerEvents(listeners)).to.throw();\n  });\n  it('registers listeners', () => {\n    const spy1 = () => sinon.spy();\n    const spy2 = (callback: any, ...args: any[]) => sinon.spy();\n\n    const listeners = [\n      {\n        name: 'my-listener-1',\n        event: 'someEvent', // event to listen to\n        handler: spy1,\n      },\n      {\n        name: 'my-listener-2',\n        event: 'someEvent',\n        handler: spy2,\n      },\n    ];\n\n    const eventManager = eventManagerProvider(emitter, { listeners });\n    eventManager.registerEvents(listeners);\n    expect(emitter.listeners('someEvent').length).to.equal(2);\n    expect(emitter.listeners('someEvent')[0]).to.equal(spy1);\n    expect(emitter.listeners('someEvent')[1]).to.equal(spy2);\n  });\n});\n\n/////////////////////////////////////////////////////\n\ndescribe('events emitting', () => {\n  let emitter: EventEmitter = null;\n  let eventManager: any = null;\n\n  beforeEach(() => {\n    emitter = new EventEmitter();\n  });\n\n  afterEach(() => {\n    emitter = null;\n    eventManager = null;\n  });\n  it('throws error when eventName argument is either null or empty string', () => {\n    const listeners: IEventListener[] = [\n      {\n        name: 'my-listener-1',\n        event: 'someEvent', // event to listen to\n        handler: () => {\n          return 'test';\n        },\n      },\n      {\n        name: 'my-listener-2',\n        event: 'someEvent',\n        handler: () => {\n          return 'test';\n        },\n      },\n      {\n        name: 'my-listener-3',\n        event: 'changeCallbackEvent', // event to listen to\n        handler: (callback, ...args) => {\n          const newCallback = (...args: any[]) => {\n            return 'changed';\n          };\n          return newCallback(...args);\n        },\n      },\n    ];\n\n    const config = {} as IEventsConfig;\n    eventManager = eventManagerProvider(emitter, config);\n    eventManager.registerEvents(listeners);\n\n    const callback = () => 'test';\n\n    expect(() => eventManager.emitEvent('', callback)).throw();\n  });\n\n  it('calls emitter.listeners with eventName argument', () => {\n    const listeners: IEventListener[] = [];\n\n    const config = {} as IEventsConfig;\n    eventManager = eventManagerProvider(emitter, config);\n    eventManager.registerEvents(listeners);\n\n    const eventName = 'someEvent';\n    const listenersMethodSpy = sinon.spy(emitter, 'listeners');\n    const callback = () => 'test';\n    eventManager.emitEvent(eventName, callback);\n    expect(listenersMethodSpy.alwaysCalledWithExactly(eventName)).to.equal(\n      true,\n    );\n  });\n\n  it('returns new callback function based on event listeners', () => {\n    const listeners: IEventListener[] = [\n      {\n        name: 'my-listener-3',\n        event: 'changeCallbackEvent', // event to listen to\n        handler: (callback, ...args) => {\n          const newCallback = (...args: any[]) => {\n            return 'changed';\n          };\n          return newCallback(...args);\n        },\n      },\n    ];\n\n    const config = {} as IEventsConfig;\n    eventManager = eventManagerProvider(emitter, config);\n    eventManager.registerEvents(listeners);\n\n    const callback = () => 'original function';\n    const cb = eventManager.emitEvent('changeCallbackEvent', callback);\n    expect(cb()).to.equal('changed');\n  });\n\n  it('calls listeners handlers without \"callback\" argument', () => {\n    const spy1 = sinon.spy();\n    const spy2 = sinon.spy();\n    const listenersWithoutCallback: IEventListener[] = [\n      {\n        name: 'my-listener-1',\n        event: 'someEvent', // event to listen to\n        handler: (callback, ...args) => {\n          return callback(...args);\n        },\n      },\n      {\n        name: 'my-listener-2',\n        event: 'someEvent',\n        handler: () => spy2(),\n      },\n    ];\n    eventManager = eventManagerProvider(emitter, {\n      listeners: listenersWithoutCallback,\n    });\n    eventManager.registerEvents(listenersWithoutCallback);\n    const callback = () => 'test';\n    eventManager.emitEvent('someEvent', callback)();\n\n    return expect(spy1.calledOnce) && expect(spy2.calledOnce);\n  });\n\n  it('works if handler returns callback call', () => {\n    const callback = () => 'test';\n\n    const listeners: IEventListener[] = [\n      {\n        name: 'my-listener-1',\n        event: 'someEvent', // event to listen to\n        handler: (callback, ...args) => {\n          return callback(...args);\n        },\n      },\n    ];\n    const config = {} as IEventsConfig;\n    eventManager = eventManagerProvider(emitter, config);\n    eventManager.registerEvents(listeners);\n    const eventFunc = eventManager.emitEvent('someEvent', callback);\n\n    expect(eventFunc()).to.equal(callback());\n  });\n\n  it('does not throw an error when callback parameter is not passed', () => {\n    const listeners: IEventListener[] = [\n      {\n        name: 'my-listener-1',\n        event: 'someEvent', // event to listen to\n        handler: () => {\n          return null;\n        },\n      },\n    ];\n    const config = {} as IEventsConfig;\n    eventManager = eventManagerProvider(emitter, config);\n    eventManager.registerEvents(listeners);\n    expect(eventManager.emitEvent('someEvent')).to.not.throw();\n  });\n});\n"
  },
  {
    "path": "packages/hadron-events/src/constants.ts",
    "content": "export enum Event {\n  HANDLE_TERMINATE_APPLICATION_EVENT = 'HANDLE_TERMINATE_APPLICATION_EVENT',\n}\n"
  },
  {
    "path": "packages/hadron-events/src/eventManagerProvider.ts",
    "content": "import { hasFunctionArgument } from './helpers/functionHelper';\nimport {\n  IEventEmitter,\n  IEventListener,\n  CallbackEvent,\n  IEventsConfig,\n  IEventManager,\n} from './types';\n\n/**\n * Provider function to inject emitter and config into variable scope\n * @param emitter event emitter\n * @param config config parameters\n */\nconst eventManagerProvider = (emitter: IEventEmitter, config: IEventsConfig) =>\n  ({\n    registerEvents: (listeners: IEventListener[]) => {\n      listeners.forEach((listener: IEventListener) => {\n        if (listener.event === '' || listener.event === null) {\n          throw new Error('eventName can not be empty');\n        }\n        emitter.on(listener.event, listener.handler);\n      });\n    },\n    emitEvent: (eventName: string, callback: CallbackEvent) => {\n      if (eventName === '' || eventName === null) {\n        throw new Error('eventName can not be empty');\n      }\n\n      if (callback === undefined || callback === null) {\n        callback = () => null;\n      }\n\n      return emitter\n        .listeners(eventName)\n        .reduce((prevCallback, currentHandler) => {\n          // is first argument called \"callback?\"\n          if (!hasFunctionArgument(currentHandler, 'callback')) {\n            return (...args: any[]) => {\n              currentHandler(...args);\n              // manually run callback\n              return prevCallback(...args);\n            };\n          }\n          return (...args: any[]) => currentHandler(prevCallback, ...args);\n        }, callback);\n    },\n  } as IEventManager);\n\nexport default eventManagerProvider;\n"
  },
  {
    "path": "packages/hadron-events/src/helpers/functionHelper.ts",
    "content": "import { getArgs } from '@brainhubeu/hadron-utils';\n\n// tslint:disable-next-line:ban-types\nfunction hasFunctionArgument(func: (args: any) => any, argumentName: string) {\n  return getArgs(func).indexOf(argumentName) >= 0;\n}\n\nexport { hasFunctionArgument };\n"
  },
  {
    "path": "packages/hadron-events/src/registerProcessEvents.ts",
    "content": "import { IEventManager } from './types';\nimport { Event } from './constants';\n\nexport default (eventEmitter: IEventManager) => {\n  process.on('exit', () => {\n    eventEmitter.emitEvent(Event.HANDLE_TERMINATE_APPLICATION_EVENT);\n  });\n};\n"
  },
  {
    "path": "packages/hadron-events/src/types.ts",
    "content": "export type CallbackEvent = (...args: any[]) => any;\nexport type EventHandler = (callback: CallbackEvent, ...args: any[]) => any;\n\nexport interface IEventEmitter {\n  listeners: (event: string) => any[];\n  on: (eventName: string, handler: EventHandler) => void;\n  emit: (eventName: string, event: object) => void;\n}\n\nexport interface IEventListener {\n  name: string;\n  event: string;\n  handler: EventHandler;\n}\n\nexport interface IHadronEventsConfig {\n  events: IEventsConfig;\n}\n\nexport interface IEventsConfig {\n  listeners: IEventListener[];\n}\n\nexport interface IEventManager {\n  registerEvents: (listeners: IEventListener[]) => null;\n  emitEvent: (eventName: string, callback?: CallbackEvent) => null;\n}\n"
  },
  {
    "path": "packages/hadron-events/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-express/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-express/README.md",
    "content": "## Installation\n\nINFO: Currently routing with hadron works only with the Express framework.\n\n```bash\nnpm install @brainhubeu/hadron-express --save\n```\n\n[More info about installation](/core/#installation)\n\n## Express integration\n\nWe need to include `hadron-express` package while initializing hadron.\n\n```javascript\nconst express = require('express');\nconst bodyParser = require('body-parser');\n\nconst port = process.env.PORT || 8080;\nconst expressApp = express();\n\nexpressApp.use(bodyParser.json());\n\nhadron(expressApp, [require('../hadron-express')], config).then((container) => {\n  expressApp.listen(port);\n});\n```\n\n## Basic routing setup\n\nTo set up routes with Hadron, we are able to include them as objects in config object under key `routes`.\n\n```javascript\nconst config = {\n  routes: {\n    helloWorldRoute: {\n      callback: () ='Hello world !',\n      methods: ['GET'],\n      path: '/',\n    },\n  },\n};\n```\n\nBasic, required structure of route config object includes:\n\n* `callback` - function called when request is made, returned value will be send as a response (except if you call `res` methods directly)\n* `methods` - array of [HTTP methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods)\n* `path` - route path\n\n## Callback\n\nThe callback function can take route parameters as an arguments. Hadron also allows us to grab a container value easily.\n\n```javascript\nrouteWithParam: {\n  callback: (firstParam) => `firstParam value: ${firstParam}`,\n  methods: ['GET'],\n  path: '/:firstParam',\n}\n```\n\nUsing this simple example, if we send a request, for example `http://localhost/foobar` will provide a response as below:\n\n```json\n\"firstParam value: foobar\"\n```\n\n---\n\nWhen you would like to implement multiple route parameters, their order as arguments in callback does not matter, argument name needs only to match parameter name.\n\n```javascript\nmultipleParams: {\n  callback: (secondParam, firstParam) =`${firstParam} ${secondParam}`,\n  methods: ['GET'],\n  path: '/:firstParam/:secondParam',\n}\n```\n\nGET request with path: `http://localhost/Hello/World` will result with following response:\n\n```json\n\"Hello World\"\n```\n\n### Locals (available from 2.0.0)\n\nAs a third parameter, hadron delivers `locals` from your response. You can inject its content in middlewares, e.g.\n\n```javascript\nconst route = {\n  callback: (req, container, locals) => locals.testValue,\n  middlewares: [\n    (req, res, next) => {\n      res.locals.testValue = 'I am test!';\n      next();\n    },\n  ],\n};\n```\n\n## Retrieving items from container in callback\n\nCallback function provides a simple way to retrieve items from container with ease. Simply set item's key as callback function's argument. Let's see an example below:\n\n```javascript\nhadron(expressApp, [require('../hadron-express')], {\n  routes: {\n    routeWithContainerValue: {\n      // sayHello argument will refer to container value\n      callback: (sayHello = `hadron says: ${sayHello}`),\n      methods: ['GET'],\n      path: '/',\n    },\n  },\n}).then((container) => {\n  // Register value under key sayHello\n  container.register('sayHello', 'Hello World');\n});\n```\n\nAfter sending a request to the `/` path, the response will look like that:\n\n```json\n\"hadron says: Hello World\"\n```\n\n---\n\nHadron will first look for request parameters and next if not found any, it will look for value in the container. So if you register a key `foo` in a container and set the route param under the same name, it will inject param's value into callback's argument foo.\n\n```javascript\ncontainer.register('foo', 'container');\n```\n\n```javascript\nexampleRoute: {\n  callback: (foo) =`foo value: ${foo}`,\n  methods: ['GET'],\n  path: '/:foo',\n},\n```\n\nResponse for `GET` request _/param_ will look like this:\n\n```json\n\"foo value: param\"\n```\n\n## Middlewares\n\n_Note: Currently middlewares only refer to express._\n\nRouting with Hadron provides a middleware support. You need to pass array with middleware functions to a `middleware` key in route config.\nFor example:\n\n```javascript\nmiddlewareExample: {\n  callback: () => {\n    console.log('Callback function');\n  },\n  methods: ['GET'],\n  middleware: [\n    (req, res, next) => {\n      console.log(`First middleware`);\n      next();\n    },\n    (req, res, next) => {\n      console.log(`Second middleware`);\n      next();\n    },\n  ],\n  path: '/',\n},\n```\n\n`GET` request to `/` will log to the console following:\n\n```sh\nFirst middleware\nSecond middleware\nCallback function\n```\n\nMiddlewares take three arguments: `request`, `response` and `next`. First two are objects and third one - function which executed continues request flow.\n\nYou can read more about middlewares in [express guide](https://expressjs.com/en/guide/using-middleware.html)\n\n## Routes nesting (available from 2.0.0)\n\nIn case of more complicated routing, hadron-express offers possibility to nest routes. That way, You can specify bunch of route properties, that all child routes will inherit.\n\nRoute properties that can be inherited:\n\n* path (will add parent's path beforehand new path),\n* middlewares\n* methods,\n\n```javascript\nconst nestedRoute = {\n  middleware: [myTestMiddleware],\n  method: ['GET'],\n  path: '/test',\n  routes: {\n    route1: {\n      // path here is going to be /test/test1/, it's going to have 'GET' method on default and middleware myTestMiddleware will be called before\n      path: '/test1',\n      callback: () => 'It works! Trust me...',\n    },\n    route1: {\n      // path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and middlewares myCustomMiddleware and myTestMiddleware will be called before\n      path: '/test2',\n      method: ['POST'],\n      middleware: [myCustomMiddleware],\n      callback: () => 'It works! Trust me...',\n    },\n  },\n};\n```\n\nIf You would like to override parent property, just define new one with `$` sign before, e.g. `$middlewares`, `$path`, `$method`.\n\n```javascript\nconst nestedRoute = {\n  middleware: [myTestMiddleware],\n  method: ['GET'],\n  path: '/test',\n  routes: {\n    route1: {\n      // path here is going to be /test1/, it's going to have 'GET' method on default and middleware myTestMiddleware will be called before\n      $path: '/test1',\n      callback: () => 'It works! Trust me...',\n    },\n    route1: {\n      // path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and no middlewares\n      path: '/test2',\n      method: ['POST'],\n      $middleware: [],\n      callback: () => 'It works! Trust me...',\n    },\n  },\n};\n```\n\nYou can define nested route endlessly, all of them will inherit properties of it's parent and other ancestors (of course if they were not overwritten with `$` sign).\n\n```javascript\nconst nestedRoute = {\n  middleware: [myTestMiddleware],\n  method: ['GET'],\n  path: '/test',\n  routes: {\n    route1: {\n      // path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and no middlewares\n      path: '/test2',\n      method: ['POST'],\n      $middleware: [],\n      callback: () => 'It works! Trust me...',\n      routes: {\n        // path here is going to be /test/test2/deep/, it's going to have 'GET' and 'POST' methods on default and no middlewares\n        deepRoute1: {\n          path: 'deep',\n          callback: () => 'The Dwarves delved too greedily and too deep',\n        },\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "packages/hadron-express/index.ts",
    "content": "import hadronExpress from './src/hadronToExpress';\nexport {\n  Callback,\n  IRoutesConfig,\n  IRoute,\n  Middleware,\n  IContainer,\n  IHadronExpressConfig,\n} from './src/types';\nimport {\n  IRoutesConfig,\n  IContainer,\n  IHadronExpressConfig,\n  RoutePathsConfig,\n} from './src/types';\n\nexport { Event } from './src/constants/eventNames';\n\nexport default hadronExpress;\n\nexport const register = (container: IContainer, config: IHadronExpressConfig) =>\n  hadronExpress(\n    {\n      routes: config.routes as IRoutesConfig,\n      routePaths: config.routePaths as RoutePathsConfig,\n    },\n    container,\n  );\n"
  },
  {
    "path": "packages/hadron-express/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-express\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Hadron module implementing express elements\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"LICENSE\"\n  ],\n  \"directories\": {\n    \"test\": \"tests\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"hadron-express\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"@brainhubeu/hadron-error-handler\": \"^1.0.0\",\n    \"@brainhubeu/hadron-events\": \"^1.0.1\",\n    \"@brainhubeu/hadron-json-provider\": \"^1.0.0\",\n    \"@brainhubeu/hadron-utils\": \"^1.0.0\",\n    \"express\": \"4.16.2\",\n    \"http-status\": \"1.1.0\"\n  },\n  \"devDependencies\": {\n    \"@types/express\": \"4.11.1\",\n    \"@types/http-status\": \"0.2.30\",\n    \"@types/multer\": \"1.3.6\",\n    \"@types/ramda\": \"0.25.23\",\n    \"@types/supertest\": \"2.0.4\",\n    \"multer\": \"1.3.0\",\n    \"ramda\": \"0.25.0\",\n    \"supertest\": \"3.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-express/src/__tests__/__mocks__/routes/route.js",
    "content": "routes = () => ({\n  testRoute: {\n    callback: () => null,\n    methods: ['GET'],\n    path: '/',\n  },\n});\n\nmodule.exports = routes;\n"
  },
  {
    "path": "packages/hadron-express/src/__tests__/createContainerProxy.ts",
    "content": "import { Container } from '@brainhubeu/hadron-core';\nimport createContainerProxy from '../createContainerProxy';\nimport * as sinon from 'sinon';\nimport { expect } from 'chai';\n\ndescribe('proxy container', () => {\n  it('calls keys() method on the container ', () => {\n    const keys = sinon.spy(Container, 'keys');\n    const containerProxy = createContainerProxy(Container);\n    containerProxy.keys();\n    expect(keys.calledOnce).to.be.equal(true);\n  });\n\n  it('calls take() method on the container', () => {\n    Container.register('key', 'item');\n    const take = sinon.spy(Container, 'take');\n    const containerProxy = createContainerProxy(Container);\n    // tslint:disable-next-line\n    containerProxy.key;\n    expect(take.calledOnce).to.be.equal(true);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-express/src/__tests__/generateMiddlewares.ts",
    "content": "import { expect } from 'chai';\nimport { isRawMiddleware, createRawMiddleware } from '../generateMiddlewares';\nimport { getArgs } from '@brainhubeu/hadron-utils';\nimport * as sinon from 'sinon';\nimport * as express from 'express';\n\ndescribe('isRawMiddleware', () => {\n  it('returns true when passed middleware is Express middleware', () => {\n    const middleware = (req, res, next) => {\n      next();\n    };\n\n    const actual = isRawMiddleware(middleware);\n\n    expect(actual).to.equal(true);\n  });\n\n  it('returns false when passed middleware is Hadron middleware', () => {\n    const middleware = (req, deps) => {\n      return;\n    };\n\n    const actual = isRawMiddleware(middleware);\n\n    expect(actual).to.equal(false);\n  });\n});\n\ndescribe('createRawMiddleware', () => {\n  it('creates Express middleware from Hadron Middleware', () => {\n    const hadronMiddleware = (req, deps) => {\n      return null;\n    };\n    const containerProxy = {};\n\n    const expressMiddleware = createRawMiddleware(\n      hadronMiddleware,\n      containerProxy,\n    );\n\n    expect(getArgs(expressMiddleware as any)).to.eql(['req', 'res', 'next']);\n  });\n\n  it('creates middleware that sends response', async () => {\n    const hadronMiddleware = (req, deps) => {\n      return {\n        status: 201,\n        body: 'hello',\n      };\n    };\n    const containerProxy = {};\n\n    const expressMiddleware = createRawMiddleware(\n      hadronMiddleware as any,\n      containerProxy,\n    );\n\n    const req = {};\n    const res = {\n      status: sinon.spy(),\n      json: sinon.spy(),\n    };\n    const next = sinon.spy();\n\n    await expressMiddleware(req as express.Request, res as any, next);\n\n    expect(res.status.firstCall.args).to.eql([201]);\n    expect(res.json.firstCall.args).to.eql(['hello']);\n  });\n\n  it('creates middleware that sets response headers and status without sending response', async () => {\n    const hadronMiddleware = (req, deps) => {\n      return {\n        type: 'PARTIAL_RESPONSE',\n        status: 300,\n        headers: {\n          'custom-header': 'foo',\n        },\n      };\n    };\n    const containerProxy = {};\n\n    const expressMiddleware = createRawMiddleware(\n      hadronMiddleware as any,\n      containerProxy,\n    );\n\n    const req = {};\n    const res = {\n      status: sinon.spy(),\n      json: sinon.spy(),\n      set: sinon.spy(),\n    };\n    const next = sinon.spy();\n\n    await expressMiddleware(req as express.Request, res as any, next);\n\n    expect(res.status.firstCall.args).to.eql([300]);\n    expect(res.set.firstCall.args).to.eql(['custom-header', 'foo']);\n    expect(res.json.called).to.equal(false);\n  });\n\n  it('creates middleware that modifies request', async () => {\n    const hadronMiddleware = (req, deps) => {\n      return {\n        type: 'PARTIAL_REQUEST',\n        values: {\n          body: 'bar',\n          customKey: 'foo',\n        },\n      };\n    };\n    const containerProxy = {};\n\n    const expressMiddleware = createRawMiddleware(\n      hadronMiddleware as any,\n      containerProxy,\n    );\n\n    const req = {\n      body: null,\n      existingKey: 'baz',\n    };\n    const res = {};\n    const next = sinon.spy();\n\n    await expressMiddleware(req as any, res as any, next);\n\n    expect(req).to.eql({\n      body: 'bar',\n      customKey: 'foo',\n      existingKey: 'baz',\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-express/src/__tests__/hadronToExpress.ts",
    "content": "import { expect } from 'chai';\n\nimport * as express from 'express';\nimport * as fs from 'fs-extra';\nimport * as HTTPStatus from 'http-status';\nimport * as multer from 'multer';\nimport * as R from 'ramda';\nimport * as sinon from 'sinon';\nimport * as request from 'supertest';\nimport { Container } from '@brainhubeu/hadron-core';\n\nimport { json as bodyParser } from 'body-parser';\n\nimport NoRouterMethodSpecifiedError from '../errors/NoRouterMethodSpecifiedError';\n\nimport routesToExpress, {\n  prepareMiddlewares,\n  preparePath,\n  prepareMethods,\n} from '../hadronToExpress';\nimport { Event } from '../constants/eventNames';\nimport { IRequest, IResponseSpec } from '../types';\n\nlet app = express();\n\nconst createTestRoute = (\n  path: string,\n  methods: string[],\n  callback: (req: IRequest, dependencies: any) => IResponseSpec,\n  middleware?: Array<(req: any, res: any, next: any) => any>,\n) => ({\n  routes: {\n    testRoute: {\n      callback,\n      methods,\n      middleware,\n      path,\n    },\n  },\n});\n\nconst getRouteProp = (expressApp: any, prop: string) =>\n  expressApp._router.stack // registered routes\n    .filter((r: any) => r.route) // take out all the middleware\n    .map((r: any) => r.route[prop]); // get all the props\n\ndescribe('router config', () => {\n  beforeEach(() => {\n    app = express();\n    app.use(bodyParser());\n    Container.register('server', app);\n    Container.register('eventManager', null);\n  });\n\n  describe('generating routes', () => {\n    it('should generate express route based on config file', () => {\n      const testRoute = createTestRoute('/index', ['GET'], () => null);\n\n      return routesToExpress(testRoute, Container).then(() =>\n        expect(getRouteProp(app, 'path')[0]).to.equal('/index'),\n      );\n    });\n\n    it('should generate correct router method based on config file', () => {\n      const testRoute = createTestRoute('/index', ['POST'], () => null);\n\n      return routesToExpress(testRoute, Container).then(() =>\n        expect(getRouteProp(app, 'methods')[0].post).to.equal(true),\n      );\n    });\n\n    it('returns status OK for request from generated route', () => {\n      const testRoute = createTestRoute('/testRequest', ['GET'], () => null);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get('/testRequest')\n        .expect(HTTPStatus.OK);\n    });\n\n    it('throws a NoRouterMethodSpecifiedError if no methods were specified', () => {\n      const testRoute = createTestRoute('/index', [], () => null);\n\n      return routesToExpress(testRoute, Container).catch((error) =>\n        expect(error).to.be.instanceOf(NoRouterMethodSpecifiedError),\n      );\n    });\n\n    it('generate multiple methods based on config', () => {\n      const callback = (req: any, res: any) =>\n        req.params.testParam + req.params.anotherParam;\n\n      const middle = sinon.spy();\n      const testRoute = createTestRoute(\n        '/testRoute',\n        ['PUT', 'DELETE'],\n        callback,\n        [middle],\n      );\n\n      routesToExpress(testRoute, Container).then(\n        () =>\n          expect(getRouteProp(app, 'methods')[0].put).to.equal(true) &&\n          expect(getRouteProp(app, 'methods')[1].delete).to.equal(true),\n      );\n    });\n\n    it('should return HTTP Status 500 if callback is not defined', () => {\n      const testRoute = createTestRoute('/testRoute', ['GET'], null);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/testRoute`)\n        .expect(HTTPStatus[500]);\n    });\n\n    it('calls emitEvent method', () => {\n      const eventManager = {\n        emitEvent: sinon.spy(),\n      };\n      Container.register('eventManager', eventManager);\n      const testRoute = createTestRoute('/index', ['GET'], () => null);\n\n      return routesToExpress(testRoute, Container).then(() =>\n        request(app)\n          .get(`/index`)\n          .then(() =>\n            expect(\n              eventManager.emitEvent.calledWith(\n                Event.HANDLE_REQUEST_CALLBACK_EVENT,\n              ),\n            ).to.equal(true),\n          ),\n      );\n    });\n\n    it('calls the response event if eventManager is present', () => {\n      const eventManager = {\n        emitEvent: sinon.spy(() => () => null),\n      };\n      Container.register('eventManager', eventManager);\n      const testRoute = createTestRoute('/index', ['GET'], () => null);\n\n      return routesToExpress(testRoute, Container).then(() =>\n        request(app)\n          .get('/index')\n          .then(() => {\n            expect(\n              eventManager.emitEvent.calledWith(Event.HANDLE_RESPONSE_EVENT),\n            ).to.equal(true);\n          }),\n      );\n    });\n\n    it('should load routes using json-provider and load them', () => {\n      routesToExpress(\n        {\n          routePaths: [\n            [\n              './packages/hadron-express/src/__tests__/__mocks__/routes/*',\n              'js',\n            ],\n          ],\n        },\n        Container,\n      );\n\n      return request(app)\n        .get(`/`)\n        .then(() => {\n          expect(getRouteProp(app, 'path')[0]).to.equal('/');\n        });\n    });\n  });\n\n  describe('routes nesting', () => {\n    describe('prepareMiddlewares()', () => {\n      it('should return parents middlewares', () => {\n        const middleware = () => null;\n        const result = prepareMiddlewares([], null, [middleware]);\n\n        expect(result).to.contain(middleware);\n      });\n\n      it('should return joined middlewares of parent and current route', () => {\n        const middleware = () => null;\n        const middleware2 = () => null;\n        const result = prepareMiddlewares([middleware2], null, [middleware]);\n\n        expect(result).to.have.members([middleware, middleware2]);\n      });\n\n      it('should exclude parent and route middleware, if $middlewares exists', () => {\n        const middleware = () => null;\n        const middleware2 = () => null;\n        const middleware3 = () => null;\n        const result = prepareMiddlewares(\n          [middleware2],\n          [middleware3],\n          [middleware],\n        );\n\n        expect(result).to.not.have.members([middleware2, middleware]);\n      });\n\n      it('should contain $middlewares, if they exists', () => {\n        const middleware = () => null;\n        const middleware2 = () => null;\n        const middleware3 = () => null;\n        const result = prepareMiddlewares(\n          [middleware2],\n          [middleware3],\n          [middleware],\n        );\n\n        expect(result).to.have.members([middleware3]);\n      });\n    });\n\n    describe('preparePath()', () => {\n      it('should return just a path of route', () => {\n        expect(preparePath('path', null, '')).to.equal('path');\n      });\n\n      it('should return merged parent path and route path', () => {\n        expect(preparePath('path', null, 'previousPath')).to.equal(\n          'previousPath/path',\n        );\n      });\n\n      it('should overwrite parent path to $path', () => {\n        expect(preparePath('path', 'path2', 'previousPath')).to.equal('path2');\n      });\n    });\n\n    describe('prepareMethods()', () => {\n      it('should return methods of route', () => {\n        expect(prepareMethods(['GET'], null, [])).to.have.members(['GET']);\n      });\n\n      it('should return join methods of route and parent route', () => {\n        expect(prepareMethods(['GET'], null, ['POST'])).to.have.members([\n          'GET',\n          'POST',\n        ]);\n      });\n\n      it('should unique methods of route and parent route', () => {\n        expect(prepareMethods(['GET'], null, ['POST', 'GET'])).to.be.length(2);\n      });\n    });\n  });\n\n  describe('router params', () => {\n    it('should pass parameter to callback func - request param', () => {\n      const callback = ({ params }) => params.valueA;\n\n      const testParam = 'This is a test';\n\n      const testRoute = createTestRoute('/index/:valueA', ['GET'], callback);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/index/${testParam}`)\n        .expect(HTTPStatus.OK)\n        .then((res: any) => {\n          expect(res.body).to.equal(testParam);\n        });\n    });\n\n    it('should pass parameter to callback func - query', () => {\n      const callback = ({ query }) => query.valueA;\n\n      const testParam = 'This is a test';\n\n      const testRoute = createTestRoute('/index', ['GET'], callback);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/index?valueA=${testParam}`)\n        .expect(HTTPStatus.OK)\n        .then((res: any) => {\n          expect(res.body).to.equal(testParam);\n        });\n    });\n\n    it('should pass multiple parameters to callback func - params', () => {\n      const callback = ({ params }) => params.valueA + params.valueB;\n\n      const testParam = 'This is a test';\n      const secondParam = ' This is a second param';\n\n      const testRoute = createTestRoute(\n        '/index/:valueA/:valueB',\n        ['GET'],\n        callback,\n      );\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/index/${testParam}/${secondParam}`)\n        .expect(HTTPStatus.OK)\n        .then((res: any) => expect(res.body).to.equal(testParam + secondParam));\n    });\n\n    it('should pass multiple parameters to callback func - query', () => {\n      const callback = ({ query }) => query.valueA + query.valueB;\n\n      const testParam = 'This is a test';\n      const secondParam = ' This is a second param';\n\n      const testRoute = createTestRoute('/index', ['GET'], callback);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/index?valueA=${testParam}&valueB=${secondParam}`)\n        .expect(HTTPStatus.OK)\n        .then((res: any) => expect(res.body).to.equal(testParam + secondParam));\n    });\n\n    it('should pass query to callback func', () => {\n      const callback = ({ query }) => query.foo;\n\n      const testQuery = 'bar';\n      const testRoute = createTestRoute('/index', ['GET'], callback);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/index/?foo=${testQuery}`)\n        .expect(HTTPStatus.OK)\n        .then((res) => {\n          expect(res.body).to.equal(testQuery);\n        });\n    });\n\n    it('should pass body to callback func', () => {\n      const callback = ({ body }) => body.testData;\n\n      const postData = {\n        testData: 'some value',\n      };\n\n      const testRoute = createTestRoute('/index', ['POST'], callback);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .post(`/index`)\n        .send(postData)\n        .expect(HTTPStatus.OK)\n        .then((res) => {\n          expect(res.body).to.equal(postData.testData);\n        });\n    });\n  });\n  describe('router middleware', () => {\n    it('calls middleware passed in router config', () => {\n      const callback = (): any => null;\n\n      const spy = sinon.spy();\n\n      const middle = (req: any, res: any, next: any) => {\n        spy();\n        next();\n      };\n\n      const testRoute = createTestRoute('/testRoute', ['GET'], callback, [\n        middle,\n      ]);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/testRoute`)\n        .expect(HTTPStatus.OK)\n        .then(() => expect(spy.called).to.be.eq(true));\n    });\n\n    it('calls multiple middlewares passed in router config', () => {\n      const callback = (): any => null;\n\n      const firstSpy = sinon.spy();\n      const secondSpy = sinon.spy();\n\n      const firstMiddleware = (req: any, res: any, next: any) => {\n        firstSpy();\n        next();\n      };\n\n      const secondMiddleware = (req: any, res: any, next: any) => {\n        secondSpy();\n        next();\n      };\n\n      const testRoute = createTestRoute('/testRoute', ['GET'], callback, [\n        firstMiddleware,\n        secondMiddleware,\n      ]);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .get(`/testRoute`)\n        .expect(HTTPStatus.OK)\n        .then(() => {\n          expect(firstSpy.called).to.be.eq(true);\n          expect(secondSpy.called).to.be.eq(true);\n        });\n    });\n  });\n\n  describe('file handling', () => {\n    const upload = multer({ dest: `${__dirname}/testUploads` });\n\n    const callback = ({ files, file }) => ({ body: files || file });\n\n    const uploadMiddleware = (req: any, res: any, next: any) =>\n      upload.any()(req, res, next);\n\n    after(() => {\n      fs.remove(`${__dirname}/testUploads`);\n    });\n\n    it('should save file passed to route', () => {\n      const testRoute = createTestRoute('/testUploads', ['POST'], callback, [\n        uploadMiddleware,\n      ]);\n\n      routesToExpress(testRoute, Container);\n      const mockDir = `${__dirname}/testUploads`;\n\n      return request(app)\n        .post('/testUploads')\n        .attach('image', `${__dirname}/__mocks__/sample.jpeg`)\n        .expect(HTTPStatus.OK)\n        .then(() => {\n          const files = fs.readdirSync(mockDir);\n          expect(files.length).to.equal(1);\n        });\n    });\n\n    it('should pass file to callback func', () => {\n      const testRoute = createTestRoute('/testUpload', ['POST'], callback, [\n        uploadMiddleware,\n      ]);\n\n      routesToExpress(testRoute, Container);\n\n      return request(app)\n        .post('/testUpload')\n        .attach('image', `${__dirname}/__mocks__/sample.jpeg`)\n        .expect(HTTPStatus.OK)\n        .then((res) => {\n          expect(R.omit(['filename', 'path', 'size'], res.body[0])).to.eql({\n            destination: `${__dirname}/testUploads`,\n            encoding: '7bit',\n            fieldname: 'image',\n            mimetype: 'image/jpeg',\n            originalname: 'sample.jpeg',\n          });\n        });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-express/src/constants/eventNames.ts",
    "content": "export enum Event {\n  HANDLE_REQUEST_CALLBACK_EVENT = 'HANDLE_REQUEST_CALLBACK_EVENT',\n  HANDLE_RESPONSE_EVENT = 'HANDLE_RESPONSE_EVENT',\n}\n"
  },
  {
    "path": "packages/hadron-express/src/constants/routing.ts",
    "content": "export enum HTTPRequestMethods {\n  GET = 'GET',\n  POST = 'POST',\n  PATCH = 'PATCH',\n  DELETE = 'DELETE',\n  PUT = 'PUT',\n}\n"
  },
  {
    "path": "packages/hadron-express/src/createContainerProxy.ts",
    "content": "import { IContainer } from './types';\n\nconst createContainerProxy = (container: IContainer): any => {\n  return new Proxy(\n    {\n      keys() {\n        return container.keys();\n      },\n    },\n    {\n      get(target: any, name) {\n        if (typeof target[name] === 'function') {\n          return target[name];\n        }\n        return container.take(name as string);\n      },\n    },\n  );\n};\n\nexport default createContainerProxy;\n"
  },
  {
    "path": "packages/hadron-express/src/declarations.d.ts",
    "content": "declare module '@hadron/events';\ndeclare module '@hadron/utils';\n"
  },
  {
    "path": "packages/hadron-express/src/errors/CreateRouteError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class CreateRouteError extends HadronErrorHandler {\n  constructor(routeName: string, error: Error) {\n    super(`Cannot create route ${routeName}.`);\n    this.stack = error.stack;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-express/src/errors/GenerateMiddlewareError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class GenerateMiddlewareError extends HadronErrorHandler {\n  constructor(error: Error) {\n    super();\n    this.name = 'GenerateMiddlewareError';\n    this.error = error;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-express/src/errors/InvalidRouteMethodError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class InvalidRouteMethodError extends HadronErrorHandler {\n  constructor(route: string, method: string) {\n    super();\n    this.message = `Invalid route method '${method}' in ${route} route`;\n    this.name = 'InvalidRouteError';\n  }\n}\n"
  },
  {
    "path": "packages/hadron-express/src/errors/NoRouterMethodSpecifiedError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class NoRouterMethodSpecifiedError extends HadronErrorHandler {\n  constructor(route: string) {\n    super();\n    this.message = `No route methods were specified for ${route} route`;\n    this.name = 'NoRouterMethodSpecifiedError';\n  }\n}\n"
  },
  {
    "path": "packages/hadron-express/src/generateMiddlewares.ts",
    "content": "import * as express from 'express';\nimport { Container } from '@brainhubeu/hadron-core';\nimport { IRoute, Middleware, HadronMiddleware } from './types';\nimport GenerateMiddlewareError from './errors/GenerateMiddlewareError';\nimport prepareRequest from './prepareRequest';\nimport handleResponseSpec from './handleResponseSpec';\nimport { getArgs } from '@brainhubeu/hadron-utils';\n\nexport const isRawMiddleware = (middleware: any) => {\n  const [firstArg, secondArg, thirdArg] = getArgs(middleware);\n\n  return (\n    (firstArg === 'req' || firstArg === 'request') &&\n    (secondArg === 'res' || secondArg === 'response') &&\n    thirdArg === 'next'\n  );\n};\n\nexport const createRawMiddleware = (\n  hadronMiddleware: HadronMiddleware,\n  containerProxy: any,\n) => {\n  return async (\n    req: express.Request,\n    res: express.Response,\n    next: express.NextFunction,\n  ) => {\n    const hadronReq = prepareRequest(req);\n    const result = await hadronMiddleware(hadronReq, containerProxy);\n\n    switch (result.type) {\n      case 'PARTIAL_REQUEST': {\n        Object.assign(req, result.values);\n        next();\n        break;\n      }\n\n      case 'PARTIAL_RESPONSE': {\n        handleResponseSpec(res)(result);\n        next();\n        break;\n      }\n\n      default: {\n        handleResponseSpec(res)(result);\n      }\n    }\n  };\n};\n\nconst generateMiddlewares = (\n  middlewares: Middleware[],\n  containerProxy: any,\n) => {\n  if (!middlewares) {\n    return middlewares;\n  }\n  return middlewares.map((middleware: any) => {\n    const rawMiddleware: Middleware = isRawMiddleware(middleware)\n      ? middleware\n      : createRawMiddleware(middleware as HadronMiddleware, containerProxy);\n\n    return (\n      req: express.Request,\n      res: express.Response,\n      next: express.NextFunction,\n    ) => {\n      Promise.resolve()\n        .then(() => rawMiddleware(req, res, next))\n        .catch((error) => {\n          const logger = Container.take('hadronLogger');\n          if (logger) {\n            logger.warn(new GenerateMiddlewareError(error));\n          }\n\n          res.sendStatus(500);\n        });\n    };\n  });\n};\n\nexport default generateMiddlewares;\n"
  },
  {
    "path": "packages/hadron-express/src/hadronToExpress.ts",
    "content": "import * as express from 'express';\nimport * as nodePath from 'path';\nimport {\n  IContainer,\n  IRoute,\n  Middleware,\n  IHadronExpressConfig,\n  IRoutesConfig,\n} from './types';\nimport { Event } from './constants/eventNames';\nimport CreateRouteError from './errors/CreateRouteError';\nimport createContainerProxy from './createContainerProxy';\nimport prepareRequest from './prepareRequest';\nimport generateMiddlewares from './generateMiddlewares';\nimport handleResponseSpec from './handleResponseSpec';\nimport jsonProvider from '@brainhubeu/hadron-json-provider';\n\nconst createRoutes = (\n  app: express.Application,\n  route: IRoute,\n  containerProxy: any,\n  routeName: string,\n) => {\n  return route.methods.map((method: string) => {\n    (app as any)[method.toLowerCase()](\n      route.path,\n      ...route.middleware,\n      (req: express.Request, res: express.Response) => {\n        const request = prepareRequest(req);\n        const eventManager = containerProxy.take('eventManager');\n\n        Promise.resolve()\n          .then(() => {\n            if (!eventManager) {\n              return route.callback(request, containerProxy, res.locals);\n            }\n\n            const newRouteCallback = eventManager.emitEvent(\n              Event.HANDLE_REQUEST_CALLBACK_EVENT,\n              route.callback,\n            );\n\n            return newRouteCallback(request, containerProxy, res.locals);\n          })\n          .then((callback) => {\n            if (!eventManager) {\n              return handleResponseSpec(res)(callback);\n            }\n\n            const newResponseHandler = eventManager.emitEvent(\n              Event.HANDLE_RESPONSE_EVENT,\n              handleResponseSpec,\n            );\n\n            return newResponseHandler(res)(callback);\n          })\n          .catch((error) => {\n            const logger = containerProxy.hadronLogger;\n            const createRouteError = new CreateRouteError(routeName, error);\n            if (logger) {\n              logger.error(createRouteError);\n            }\n            res.sendStatus(500);\n          });\n      },\n    );\n  });\n};\n\nconst convertToExpress = (\n  config: IHadronExpressConfig,\n  container: IContainer,\n) => {\n  const app = container.take('server');\n  const promises: Array<Promise<object>> = [];\n  const containerProxy = createContainerProxy(container);\n  if (config.routes) {\n    promises.push(Promise.resolve(config.routes));\n  }\n\n  if (config.routePaths) {\n    const paths: string[] = [];\n    const extensions: string[] = [];\n    (config.routePaths as any).forEach((path: string[]) => {\n      paths.push(path[0]);\n      if (path.length > 1) {\n        extensions.push(path[1]);\n      }\n    });\n\n    promises.push(jsonProvider(paths, extensions));\n  }\n\n  return (\n    Promise.all(promises)\n      .then((results) =>\n        results.reduce(\n          (accumulator, current) => ({ ...accumulator, ...current }),\n          {},\n        ),\n      )\n      // flatten routes and prepare all components\n      .then((routes: any) =>\n        (Object as any)\n          .keys(routes)\n          .map((key: string) => prepareRoute(routes[key], key, containerProxy))\n          .reduce((accumulator: any, current: any) => ({\n            ...accumulator,\n            ...current,\n          })),\n      )\n      .then((preparedRoutes: IRoutesConfig) => {\n        (Object as any).keys(preparedRoutes).map((key: string) => {\n          const route: IRoute = preparedRoutes[key];\n          createRoutes(app, route, container, key);\n        });\n      })\n  );\n};\n\nconst prepareRoute = (\n  route: IRoute,\n  key: string,\n  container: IContainer,\n  parentRoute: IRoute = {},\n  parentKey: string = null,\n) => {\n  const middlewares = prepareMiddlewares(\n    generateMiddlewares(route.middleware, container),\n    generateMiddlewares(route.$middleware, container),\n    parentRoute.middleware,\n  );\n  const path = preparePath(route.path, route.$path, parentRoute.path);\n\n  const methods = prepareMethods(\n    route.methods,\n    route.$methods,\n    parentRoute.methods,\n  );\n\n  const routeKey = parentKey ? `${parentKey}.${key}` : key;\n\n  const preparedRoute = {\n    ...route,\n    path,\n    methods,\n    middleware: middlewares,\n  };\n\n  const result = {\n    [routeKey]: preparedRoute,\n  };\n\n  if (route.routes) {\n    return {\n      ...result,\n      ...(Object as any)\n        .keys(route.routes)\n        .map((childKey: string) =>\n          prepareRoute(\n            (route.routes as any)[childKey],\n            childKey,\n            container,\n            preparedRoute,\n            routeKey,\n          ),\n        )\n        .reduce((accumulator: any, current: any) => ({\n          ...accumulator,\n          ...current,\n        })),\n    };\n  }\n\n  return result;\n};\n\nexport const prepareMiddlewares = (\n  middleware: any[],\n  $middleware: any[],\n  parentMiddleware: Middleware[],\n) => {\n  if ($middleware) {\n    return $middleware;\n  }\n  return [...(parentMiddleware || []), ...(middleware || [])];\n};\n\nexport const preparePath = (\n  path: string,\n  $path: string,\n  parentPath: string = '',\n) => {\n  if ($path) {\n    return $path;\n  }\n  return nodePath.join(parentPath, path);\n};\n\nexport const prepareMethods = (\n  methods: string[],\n  $methods: string[],\n  parentMethods: string[] = [],\n) => {\n  if ($methods) {\n    return $methods;\n  }\n  return [...(methods || []), ...parentMethods].reduce(\n    (accumulator, next) =>\n      accumulator.indexOf(next) >= 0 ? accumulator : [...accumulator, next],\n    [],\n  );\n};\n\nexport default convertToExpress;\n"
  },
  {
    "path": "packages/hadron-express/src/handleResponseSpec.ts",
    "content": "import * as express from 'express';\nimport * as HTTPStatus from 'http-status';\nimport { IResponseSpec, IPartialResponseSpec } from './types';\n\nconst getClass = (val: any) => Object.prototype.toString.call(val).slice(8, -1);\n\nconst isPrimitive = (val: any) => {\n  return ['String', 'Number', 'Null', 'Undefined'].includes(getClass(val));\n};\n\nconst handleResponseSpec = (res: express.Response) => (\n  responseSpec: IResponseSpec | IPartialResponseSpec,\n) => {\n  if (isPrimitive(responseSpec)) {\n    return res.json(responseSpec);\n  }\n\n  const status = responseSpec.status\n    ? responseSpec.status\n    : responseSpec.type === 'RESPONSE' && responseSpec.redirect\n      ? HTTPStatus.FOUND\n      : HTTPStatus.OK;\n  const headers = responseSpec.headers || {};\n\n  Object.keys(headers).forEach((headerName) => {\n    res.set(headerName, headers[headerName]);\n  });\n\n  res.status(status);\n\n  if (responseSpec.type === 'PARTIAL_RESPONSE') {\n    return;\n  }\n\n  const body = responseSpec.body || {};\n\n  if (responseSpec.redirect) {\n    return res.redirect(responseSpec.redirect);\n  }\n\n  if (responseSpec.view) {\n    const { name, bindings } = responseSpec.view;\n    return res.render(name, bindings);\n  }\n\n  res.json(body);\n};\n\nexport default handleResponseSpec;\n"
  },
  {
    "path": "packages/hadron-express/src/prepareRequest.ts",
    "content": "import * as express from 'express';\nimport { IRequest } from './types';\n\nconst prepareRequest = (\n  expressRequest: express.Request,\n  locals = {},\n): IRequest => {\n  return {\n    locals,\n    headers: expressRequest.headers,\n    body: expressRequest.body,\n    params: expressRequest.params,\n    query: expressRequest.query,\n    file: expressRequest.file,\n    files: expressRequest.files,\n  };\n};\n\nexport default prepareRequest;\n"
  },
  {
    "path": "packages/hadron-express/src/types.ts",
    "content": "import * as express from 'express';\n\nexport type Middleware = (\n  req: express.Request,\n  res: express.Response,\n  next: express.NextFunction,\n) => any;\n\nexport type Callback = (...args: any[]) => any;\n\nexport interface IRoute {\n  callback?: Callback;\n  middleware?: Middleware[];\n  $middleware?: Middleware[];\n  path?: string;\n  $path?: string;\n  methods?: string[];\n  $methods?: string[];\n  routes?: IRoutesConfig[];\n}\n\nexport interface IRoutesConfig {\n  [key: string]: IRoute;\n}\n\nexport type RoutePathsConfig = string[][];\n\nexport interface IContainer {\n  take: (key: string) => any;\n  keys: () => string[];\n}\n\nexport interface IHeaders {\n  [headerName: string]: string;\n}\n\nexport interface IView {\n  name: string;\n  bindings?: any;\n}\n\nexport type StatusCode =\n  | 100\n  | 101\n  | 102\n  | 200\n  | 201\n  | 202\n  | 203\n  | 204\n  | 205\n  | 206\n  | 207\n  | 208\n  | 226\n  | 300\n  | 301\n  | 302\n  | 303\n  | 304\n  | 305\n  | 307\n  | 308\n  | 400\n  | 401\n  | 402\n  | 403\n  | 404\n  | 405\n  | 406\n  | 407\n  | 408\n  | 409\n  | 410\n  | 411\n  | 412\n  | 413\n  | 414\n  | 415\n  | 416\n  | 417\n  | 418\n  | 421\n  | 422\n  | 423\n  | 424\n  | 425\n  | 426\n  | 428\n  | 429\n  | 431\n  | 451\n  | 500\n  | 501\n  | 502\n  | 503\n  | 504\n  | 505\n  | 506\n  | 507\n  | 508\n  | 509\n  | 510\n  | 511;\n\nexport interface IResponseSpec {\n  type: 'RESPONSE';\n  status?: StatusCode;\n  redirect?: string;\n  headers?: IHeaders;\n  body?: any;\n  view?: IView;\n}\n\nexport interface IPartialResponseSpec {\n  type: 'PARTIAL_RESPONSE';\n  status?: StatusCode;\n  headers?: IHeaders;\n}\n\nexport interface IRequest {\n  locals?: any;\n  headers?: any;\n  body?: any;\n  params?: any[];\n  query?: any[];\n  file?: any;\n  files?: any;\n}\n\nexport interface IPartialRequest {\n  type: 'PARTIAL_REQUEST';\n  values: {\n    [key: string]: any;\n  };\n}\nexport interface IHadronExpressConfig {\n  routes?: IRoutesConfig;\n  routePaths?: RoutePathsConfig;\n}\n\nexport type MiddlewareResult =\n  | IPartialResponseSpec\n  | IPartialRequest\n  | IResponseSpec;\n\nexport type HadronMiddleware = (\n  request: IRequest,\n  dependencies: any,\n) => MiddlewareResult;\n"
  },
  {
    "path": "packages/hadron-express/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-file-locator/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-file-locator/README.md",
    "content": "# Hadron file locator\n\nIt's just part of hadron-json-provider\n"
  },
  {
    "path": "packages/hadron-file-locator/index.ts",
    "content": "import locate, { configLocate } from './src/file-locator';\n\nexport default locate;\nexport { configLocate };\n"
  },
  {
    "path": "packages/hadron-file-locator/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-file-locator\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hadron module for searching file paths in directories\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-file-locator\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"glob\": \"7.1.2\"\n  },\n  \"devDependencies\": {\n    \"@types/glob\": \"5.0.35\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/file-locator.ts",
    "content": "import { expect } from 'chai';\nimport { configLocate } from '../file-locator';\n\ndescribe('locate', () => {\n  const packageDirPath = 'packages/hadron-file-locator/src/__tests__';\n\n  it('should return an array', () => {\n    return configLocate(['./mock/app/config/*'], 'config', 'development').then(\n      (result) => {\n        expect(result).to.be.an('array');\n      },\n    );\n  });\n\n  it('should return path files from mock/app/conifg/* with development type and js extension', () => {\n    return configLocate(\n      [`${packageDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['JS'],\n    ).then((result) => {\n      expect(result).to.deep.equal([\n        `${packageDirPath}/mock/app/config/config.js`,\n        `${packageDirPath}/mock/app/config/config_development.js`,\n      ]);\n    });\n  });\n\n  it('should return path files from mock/app/config/* with development type and json extension', () => {\n    return configLocate(\n      [`${packageDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['json'],\n    ).then((result) => {\n      expect(result).to.deep.equal([\n        `${packageDirPath}/mock/app/config/config.json`,\n        `${packageDirPath}/mock/app/config/config_development.json`,\n      ]);\n    });\n  });\n\n  it('should return path files from every folder in mock/plugins with config folder', () => {\n    return configLocate(\n      [`${packageDirPath}/mock/plugins/*/config/*`],\n      'config',\n      'development',\n      ['js'],\n    ).then((result) => {\n      expect(result).to.deep.equal([\n        `${packageDirPath}/mock/plugins/plugin1/config/config.js`,\n        `${packageDirPath}/mock/plugins/plugin1/config/config_development.js`,\n        `${packageDirPath}/mock/plugins/plugin2/config/config.js`,\n        `${packageDirPath}/mock/plugins/plugin2/config/config_development.js`,\n        `${packageDirPath}/mock/plugins/plugin3/config/config.js`,\n        `${packageDirPath}/mock/plugins/plugin3/config/config_development.js`,\n      ]);\n    });\n  });\n\n  it('should return path files from mock/app/ext with js, json and xml extensions', () => {\n    return configLocate(\n      [`${packageDirPath}/mock/app/ext/*`],\n      'config',\n      'development',\n      ['js', 'json', 'xml'],\n    ).then((result) => {\n      expect(result).to.deep.equal([\n        `${packageDirPath}/mock/app/ext/config.js`,\n        `${packageDirPath}/mock/app/ext/config.json`,\n        `${packageDirPath}/mock/app/ext/config.xml`,\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config.js",
    "content": "const x = () => {\n    return {\n        usernameJS: \"user-JS\",\n        emailJS: \"user-JS@email.com\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config.json",
    "content": "{\n    \"status\": \"Default\",\n    \"database\": {\n        \"host\": \"default\",\n        \"user\": \"default\",\n        \"password\": \"default\"\n    }\n}"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config.xml",
    "content": "<status>Test</status>\n"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config_development.js",
    "content": "const x = () => {\n    return {\n        name: \"module - x\"\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config_development.json",
    "content": "{\n    \"status\": \"Development\",\n    \"onlyDevelopmentProp\": \"I am developer!\"\n}\n"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/ext/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/ext/config.json",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/ext/config.xml",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/universal/dog.config.js",
    "content": "const x = () => {\n    return {\n        dogName: \"Rex\",\n    }\n}\n\nmodule.exports = x;\n"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/universal/other.json",
    "content": "{\n    \"fromJSON\": true\n}"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/universal/team.config.js",
    "content": "const x = () => {\n    return {\n        teamName: \"team1\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/universal/test.js",
    "content": "const x = () => {\n    return {\n        name: \"TEST\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/app/universal/user.config.js",
    "content": "const x = () => {\n    return {\n        userName: \"user1\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin1/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin1/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin1/config/config_development.ts",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin1/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin2/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin2/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin2/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin3/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin3/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/__tests__/mock/plugins/plugin3/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-file-locator/src/declarations.d.ts",
    "content": "declare module 'glob';\n"
  },
  {
    "path": "packages/hadron-file-locator/src/file-locator.ts",
    "content": "import glob from './glob-promise';\n\nconst addExtension = (paths: string[], extensions: string[]): string[] =>\n  paths.reduce(\n    (accumulator, currentPath) => [\n      ...accumulator,\n      ...extensions.map((ext) => `${currentPath}.${ext.toLowerCase()}`),\n    ],\n    [],\n  );\n\nconst filterPaths = (data: string[], configName: string, type: string) =>\n  new Promise((resolve, reject) => {\n    const arr: string[] = [];\n\n    data.forEach((element) => {\n      const fileName = element\n        .split('/')\n        [element.split('/').length - 1].split('.')[0];\n\n      if (fileName === configName) {\n        arr.push(element);\n      } else if (fileName.includes('_')) {\n        if (\n          fileName.split('_')[0] === configName &&\n          fileName.split('_')[1] === type\n        ) {\n          arr.push(element);\n        }\n      }\n    });\n\n    resolve(arr);\n  });\n\nconst flattenDeep = (arr: any[]): any[] =>\n  Array.isArray(arr)\n    ? arr.reduce((a, b) => [...flattenDeep(a), ...flattenDeep(b)], [])\n    : [arr];\n\nexport const configLocate = (\n  paths: string[],\n  configName: string,\n  type: string,\n  extensions: string[] = [],\n): Promise<any> =>\n  new Promise((resolve, reject) => {\n    paths.map((path) => path.toLowerCase());\n    if (extensions.length > 0) {\n      paths = addExtension(paths, extensions);\n    }\n\n    Promise.all(paths.map(glob)).then((data) => {\n      filterPaths(\n        flattenDeep(data.map((el) => el.sort())),\n        configName,\n        type,\n      ).then(resolve);\n    });\n  });\n\nexport const locate = (\n  paths: string[],\n  extensions: string[] = [],\n): Promise<any> =>\n  new Promise((resolve, reject) => {\n    paths.map((path) => path.toLowerCase());\n\n    if (extensions.length > 0) {\n      paths = addExtension(paths, extensions);\n    }\n\n    Promise.all(paths.map(glob))\n      .then((data) => flattenDeep(data.map((el) => el.sort())))\n      .then(resolve);\n  });\n\nexport default locate;\n"
  },
  {
    "path": "packages/hadron-file-locator/src/glob-promise.ts",
    "content": "import * as glob from 'glob';\n\nconst promise = (pattern: string): Promise<any> =>\n  new Promise(\n    (resolve, reject) =>\n      new glob.Glob(\n        pattern,\n        (err: Error, data: string[]) =>\n          err === null ? resolve(data) : reject(err),\n      ),\n  );\n\nexport default promise;\n"
  },
  {
    "path": "packages/hadron-file-locator/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-json-provider/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-json-provider/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-json-provider --save\n```\n\n[More info about installation](/core/#installation)\n\n## Overview\n\nJSON Provider allows you to automatically load multiple files as JSON object, with file names as object keys, and files data as object values.\nCurrently we support following extensions:\n\n* `.js`\n* `.json`\n* `.xml`\n\n## Module functions\n\n### Basic provider\n\n```javascript\njsonProvider(paths, extensions);\n```\n\n* `paths` - array of strings which contains paths to files\n* `extensions` - array of strings which contains extensions of files from which you want to build an JSON object\n\nFor example, having directory with the following structure:\n\n![Directory structure](img/routing.png)\n\nTo find all files in `./routing` and its sub-directories with extension `config.js` you can use following code:\n\n```javascript\njsonProvider(['./routing/**/*'], ['config.js'])\n  .then((object) => {})\n  .catch((error) => {});\n```\n\n### Configuration Provider\n\n```javascript\nconfigJsonProvider(paths, configFile, projectType, extensions);\n```\n\n* `paths` - array of strings which contains paths to files\n* `configFile` - name of main configuration file\n* `projectType` - project type\n* `extensions` - array of strings which contains extensions of files from which you want to build an JSON object\n\nFor example, having directory with the following structure:\n\n![Directory structure](img/routingType.png)\n\nIf you want to build configuration object which depends on project type, for example `development` you can use following code\n\n```javascript\nconfigJsonProvider(['./app/config/*'], 'config', 'development', ['xml', 'js'])\n  .then((object) => {})\n  .catch((error) => {});\n```\n"
  },
  {
    "path": "packages/hadron-json-provider/index.ts",
    "content": "import jsonProvider, {\n  configJsonProvider,\n  jsLoader,\n  jsonLoader,\n  xmlLoader,\n} from './src/json-provider';\n\nexport default jsonProvider;\nexport { configJsonProvider, jsLoader, jsonLoader, xmlLoader };\n"
  },
  {
    "path": "packages/hadron-json-provider/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-json-provider\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hadron json provider module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-json-provider\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-file-locator\": \"^1.0.0\",\n    \"xml2js\": \"0.4.19\"\n  },\n  \"devDependencies\": {\n    \"@types/xml2js\": \"0.4.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/config-json-provider.ts",
    "content": "import { expect } from 'chai';\nimport { configJsonProvider } from '../json-provider';\n\ndescribe('configJsonProvider', () => {\n  const mockDirPath = 'packages/hadron-json-provider/src/__tests__';\n  it('should return object', () => {\n    return configJsonProvider(\n      [`${mockDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['js'],\n    ).then((result) => {\n      expect(result).to.be.an.instanceof(Object);\n    });\n  });\n\n  it('should return JavaScript object with proper values', () => {\n    const validObject = {\n      emailJS: 'user-JS@email.com',\n      name: 'module - x',\n      usernameJS: 'user-JS',\n    };\n\n    return configJsonProvider(\n      [`${mockDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['js'],\n    ).then((result) => {\n      expect(result).to.be.deep.equal(validObject);\n    });\n  });\n\n  it('should return JavaScript object from json and xml files', () => {\n    const validObject = {\n      database: {\n        host: 'default',\n        password: 'default',\n        user: 'default',\n      },\n      status: 'Test',\n    };\n\n    return configJsonProvider(\n      [`${mockDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['json', 'xml'],\n    ).then((result) => {\n      expect(result).to.be.deep.equal(validObject);\n    });\n  });\n\n  it('should return JavaScript object from json and js files', () => {\n    const validObject = {\n      database: {\n        host: 'default',\n        password: 'default',\n        user: 'default',\n      },\n      emailJS: 'user-JS@email.com',\n      name: 'module - x',\n      status: 'Development',\n      usernameJS: 'user-JS',\n    };\n\n    return configJsonProvider(\n      [`${mockDirPath}/mock/app/config/*`],\n      'config',\n      'development',\n      ['json', 'js'],\n    ).then((result) => {\n      expect(result).to.be.deep.equal(validObject);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/js-loader.ts",
    "content": "import { expect } from 'chai';\nimport { jsLoader } from '../json-provider';\n\ndescribe('jsLoader', () => {\n  const mockDirPath = 'packages/hadron-json-provider/src/__tests__';\n  it('should return object', () => {\n    return jsLoader(`${mockDirPath}/mock/app/config/config.js`).then(\n      (result) => {\n        expect(result).to.be.an.instanceof(Object);\n      },\n    );\n  });\n\n  it('load JavaScript file and return callback result', () => {\n    return jsLoader(`${mockDirPath}/mock/app/config/config.js`).then(\n      (result) => {\n        expect(result).to.be.deep.equal({\n          emailJS: 'user-JS@email.com',\n          usernameJS: 'user-JS',\n        });\n      },\n    );\n  });\n\n  it('should load a JavaScript file with default export', () => {\n    return jsLoader(\n      `${mockDirPath}/mock/app/universal/exportDefaultConfig.js`,\n    ).then((result) => {\n      expect(result).to.be.deep.equal({\n        emailJS: 'user-JS@email.com',\n        usernameJS: 'user-JS',\n      });\n    });\n  });\n\n  it(\"should throw error if file path doesn't have a valid extension\", () => {\n    const path = `${mockDirPath}/mock/app/config/config.json`;\n    return jsLoader(path).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n      expect(error.message).to.be.equal(`${path} doesn't have js extension`);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/json-loader.ts",
    "content": "import { expect } from 'chai';\nimport { jsonLoader } from '../json-provider';\n\ndescribe('jsonLoader', () => {\n  const path =\n    'packages/hadron-json-provider/src/__tests__/mock/app/config/config_development.json';\n\n  it('should return an object', () => {\n    return jsonLoader(path).then((result) => {\n      expect(result).to.be.an.instanceof(Object);\n    });\n  });\n\n  it('load json file and return callback result', () => {\n    return jsonLoader(path).then((result) => {\n      expect(result).to.be.deep.equal({\n        status: 'Development',\n      });\n    });\n  });\n\n  it('should throw an error when extension is invalid', () => {\n    return jsonLoader(`${path}x`).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n      expect(error.message).to.be.equal(\n        `${path}x doesn't have a json extension`,\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/json-provider.ts",
    "content": "import { expect } from 'chai';\nimport jsonProvider from '../json-provider';\n\ndescribe('jsonProvider', () => {\n  const mockDirPath = 'packages/hadron-json-provider/src/__tests__';\n  it(\"should return object from config files, supports custom paths (like 'config.js')\", () => {\n    const finalObject = {\n      dogName: 'Rex',\n      teamName: 'team1',\n      userName: 'user1',\n    };\n\n    return jsonProvider(\n      [`${mockDirPath}/mock/app/universal/*`],\n      ['config.js'],\n    ).then((object) => {\n      expect(object).to.be.deep.equal(finalObject);\n    });\n  });\n\n  it('should return empty object if files do not exists', () => {\n    return jsonProvider(['a/b/c'], ['js']).then((data) =>\n      expect(data).to.be.deep.equal({}),\n    );\n  });\n\n  it('should combine configurations from different extensions', () => {\n    const finalObject = {\n      dogName: 'Rex',\n      fromJSON: true,\n      teamName: 'team1',\n      userName: 'user1',\n    };\n\n    return jsonProvider(\n      [`${mockDirPath}/mock/app/universal/*`],\n      ['config.js', 'json'],\n    ).then((object) => {\n      expect(object).to.be.deep.equal(finalObject);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config.js",
    "content": "const x = () => {\n    return {\n        usernameJS: \"user-JS\",\n        emailJS: \"user-JS@email.com\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config.json",
    "content": "{\n    \"status\": \"Default\",\n    \"database\": {\n        \"host\": \"default\",\n        \"user\": \"default\",\n        \"password\": \"default\"\n    }\n}"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config.xml",
    "content": "<status>Test</status>\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config_development.js",
    "content": "const x = () => {\n    return {\n        name: \"module - x\"\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config_development.json",
    "content": "{\n    \"status\": \"Development\"\n}"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/ext/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/ext/config.json",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/ext/config.xml",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/dog.config.js",
    "content": "const x = () => {\n    return {\n        dogName: \"Rex\",\n    }\n}\n\nmodule.exports = x;\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/exportDefaultConfig.js",
    "content": "const x = () => {\n  return {\n    usernameJS: 'user-JS',\n    emailJS: 'user-JS@email.com',\n  };\n};\n\nmodule.exports.default = x;\n"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/other.json",
    "content": "{\n    \"fromJSON\": true\n}"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/team.config.js",
    "content": "const x = () => {\n    return {\n        teamName: \"team1\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/test.js",
    "content": "const x = () => {\n    return {\n        name: \"TEST\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/app/universal/user.config.js",
    "content": "const x = () => {\n    return {\n        userName: \"user1\",\n    }\n}\n\nmodule.exports = x;"
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin1/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin1/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin1/config/config_development.ts",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin1/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin2/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin2/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin2/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin3/config/config.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin3/config/config_development.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/mock/plugins/plugin3/config/config_test.js",
    "content": ""
  },
  {
    "path": "packages/hadron-json-provider/src/__tests__/xml-loader.ts",
    "content": "import { expect } from 'chai';\nimport { xmlLoader } from '../json-provider';\n\ndescribe('xmlLoader', () => {\n  const path =\n    'packages/hadron-json-provider/src/__tests__/mock/app/config/config.xml';\n\n  it('should return object', () => {\n    return xmlLoader(path).then((result) => {\n      expect(result).to.be.an.instanceof(Object);\n    });\n  });\n\n  it('load XML file and return callback result', () => {\n    return xmlLoader(path).then((result) => {\n      expect(result).to.be.deep.equal({\n        status: 'Test',\n      });\n    });\n  });\n\n  it(\"should throw error if file path doesn't have a valid extension\", () => {\n    return xmlLoader(`${path}x`).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n      expect(error.message).to.be.equal(`${path}x doesn't have xml extension`);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-json-provider/src/declarations.d.ts",
    "content": "declare module 'xml2js';\ndeclare module '@hadron/file-locator';\n"
  },
  {
    "path": "packages/hadron-json-provider/src/json-provider.ts",
    "content": "import * as fs from 'fs';\nimport { extname, relative } from 'path';\nimport { parseString as xmlToJson } from 'xml2js';\nimport locate, { configLocate } from '@brainhubeu/hadron-file-locator';\n\nconst isFunction = (functionToCheck: any): boolean =>\n  functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';\n\nconst getExtension = (path: string): string => extname(path).substring(1);\n\nexport const jsLoader = (path: string) => {\n  const supportsExtension: string = 'js';\n  return new Promise((resolve, reject) => {\n    if (getExtension(path) !== supportsExtension) {\n      reject(new Error(`${path} doesn't have ${supportsExtension} extension`));\n    }\n\n    let data = require(`./${relative(__dirname, path)}`);\n    if (!isFunction(data) && data && isFunction(data.default)) {\n      data = data.default;\n    }\n    data !== null ? resolve(data()) : reject(new Error('File not found'));\n  });\n};\n\nexport const jsonLoader = (path: string) => {\n  const supportsExtension: string = 'json';\n  return new Promise((resolve, reject) => {\n    if (getExtension(path) !== supportsExtension) {\n      reject(\n        new Error(`${path} doesn't have a ${supportsExtension} extension`),\n      );\n    }\n\n    fs.readFile(path, 'utf8', (err, data) => {\n      err ? reject(err) : resolve(JSON.parse(data));\n    });\n  });\n};\n\nexport const xmlLoader = (path: string) => {\n  const supportsExtension: string = 'xml';\n  return new Promise((resolve, reject) => {\n    if (getExtension(path) !== supportsExtension) {\n      reject(new Error(`${path} doesn't have ${supportsExtension} extension`));\n    }\n\n    fs.readFile(path, 'utf8', (err, data) => {\n      if (err) {\n        reject(err);\n      }\n\n      xmlToJson(data, (jsonErr: Error, jsonData: string) => {\n        if (jsonErr) {\n          reject(jsonErr);\n        }\n        resolve(jsonData);\n      });\n    });\n  });\n};\n\nconst mapper: { [key: string]: (path: string) => Promise<any> } = {\n  js: jsLoader,\n  json: jsonLoader,\n  xml: xmlLoader,\n};\n\nconst extensionMapper = (paths: string[]): Array<Promise<any>> =>\n  paths.map((path) => mapper[getExtension(path)](path));\n\nexport const configJsonProvider = (\n  paths: string[],\n  configName: string,\n  type: string,\n  extensions: string[] = [],\n  concatResults: boolean = false,\n): Promise<object> =>\n  configLocate(paths, configName, type, extensions)\n    .then((locatedPaths: string[]) =>\n      Promise.all(extensionMapper(locatedPaths)),\n    )\n    .then(\n      (data: any) => (concatResults ? [...data] : Object.assign({}, ...data)),\n    );\n\nexport const jsonProvider = (\n  paths: string[],\n  extensions: string[],\n  concatResults: boolean = false,\n) =>\n  locate(paths, extensions)\n    .then((locatedPaths: string[]) =>\n      Promise.all(extensionMapper(locatedPaths)),\n    )\n    .then(\n      (data: any) => (concatResults ? [...data] : Object.assign({}, ...data)),\n    );\n\nexport default jsonProvider;\n"
  },
  {
    "path": "packages/hadron-json-provider/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-logger/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-logger/README.md",
    "content": "# Logger for Hadron\n\n## Overview\n\nHadron Logger provides an option to replace the default hadron logger ([bunyan](https://github.com/trentm/node-bunyan)) to the one of your choice.\n\n## Installation\n\n```bash\nnpm install @brainhubeu/hadron-logger --save\n```\n\n[More info about installation](http://hadron-docs.dev.brainhub.pl/core/#installation)\n\n## Initialization\n\nPass the package as an argument for the Hadron bootstrapping function:\n\n```javascript\n// ... importing and initializing other components\n\nhadron(expressApp, [require('@brainhubeu/hadron-logger')], config);\n```\n\nThat way, you should be able to get it from the [Container](http://hadron-docs.dev.brainhub.pl/core/#dependency-injection) like that:\n\n```javascript\nconst logger = container.take('logger');\nlogger.log('Hello, I am your logger');\nlogger.warm('Look out! I am your logger!');\nlogger.debug('Am I your logger?');\nlogger.error('I am not your logger!');\n```\n\nNotice: `logger` is a container key only for the default logger.\n\n## Configuration\n\nTo setup your own logger, you need to provide an adapter first. You can do that by importing the `registerAdapter` method and calling it with name and provider function for your logger, like that:\n\n```javascript\nconst registerAdapter = require('@brainhubeu/hadron-logger').registerAdapter;\nregisterAdapter('myOwnLogger', function(config) {\n  return {\n    log: function(message) {\n      console.log(message);\n    },\n    warn: function(message) {\n      console.warn(message);\n    },\n    debug: function(message) {\n      console.debug(message);\n    },\n    error: function(message) {\n      console.error(message);\n    },\n  };\n});\n```\n\nProvider takes the Hadron logger config as the first parameter.\n\nAfter your adapter is set up, you can define your logger in the Hadron configuration and retrieve it using the logger's name.\n\n```javascript\nconst hadronConfig = {\n  // ...other stuff\n  logger: {\n    name: 'myLoggerName',\n    type: 'myOwnLogger',\n  },\n};\n\n// hadron initialization\n\nconst logger = Container.take('myLoggerName');\n```\n\n## Multiple loggers\n\nYou can define multiple loggers for your application. To do that you just need to provide adapters for each of them and define them in the configuration.\n\n```javascript\nconst hadronConfig = {\n  // ...other stuff\n  logger: [\n    { name: 'Logger1', type: 'logger1' },\n    { name: 'logger2', type: 'logger2' },\n    { name: 'logger3', type: 'logger3' },\n  ],\n};\n\n// hadron initialization\n\ncontainer.take('Logger1');\ncontainer.take('Logger2');\ncontainer.take('Logger3');\n```\n"
  },
  {
    "path": "packages/hadron-logger/index.ts",
    "content": "import logger, { register, registerAdapter } from './src/logger';\nimport { ILogger, ILoggerConfig, ILoggerFactory } from './src/types';\n\nexport default logger;\n\nexport { register, ILogger, ILoggerConfig, ILoggerFactory, registerAdapter };\n"
  },
  {
    "path": "packages/hadron-logger/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-logger\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Hadron logger\",\n  \"target\": \"dist\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"logger\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"@brainhubeu/hadron-error-handler\": \"^1.0.0\",\n    \"bunyan\": \"^1.8.12\"\n  },\n  \"devDependencies\": {\n    \"@types/bunyan\": \"^1.8.4\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-logger/src/__tests__/logger.ts",
    "content": "import { expect, assert } from 'chai';\nimport { Container } from '@brainhubeu/hadron-core';\nimport { register, registerAdapter } from '../logger';\nimport LoggerNameIsRequiredError from '../errors/LoggerNameIsRequiredError';\nimport LoggerAdapterNotDefinedError from '../errors/LoggerAdapterNotDefinedError';\nimport CouldNotRegisterLoggerInContainerError from '../errors/CouldNotRegisterLoggerInContainerError';\nimport ConfigNotDefinedError from '../errors/ConfigNotDefinedError';\nimport { ILogger } from '../types';\n\ndescribe('logger', () => {\n  beforeEach(() => {\n    Container.register('firstlogger', '');\n    Container.register('firstLogger', '');\n    Container.register('secondLogger', '');\n    Container.register('UnknownTypeLogger', '');\n  });\n\n  it('should register logger under \"firstlogger\"', () => {\n    register(Container, {\n      logger: {\n        name: 'firstlogger',\n        type: 'bunyan',\n      },\n    });\n    assert(Container.take('firstlogger'));\n  });\n\n  it('should register multiple loggers', () => {\n    register(Container, {\n      logger: [\n        {\n          name: 'firstLogger',\n          type: 'bunyan',\n        },\n        {\n          name: 'secondLogger',\n          type: 'bunyan',\n        },\n      ],\n    });\n\n    assert(Container.take('firstLogger'));\n    assert(Container.take('secondLogger'));\n  });\n\n  it('when there is no name provided in config then should throw LoggerNameIsRequiredError', () => {\n    expect(() => {\n      register(Container, {\n        logger: {\n          type: 'bunyan',\n        },\n      } as any);\n    }).to.throw(LoggerNameIsRequiredError);\n  });\n\n  it('when there is no type of logger, should register it with default logger', () => {\n    register(Container, {\n      logger: {\n        name: 'firstLogger',\n      },\n    } as any);\n    assert(Container.take('firstLogger'));\n  });\n\n  it('when logger is defined with type that has not any adapter then should throw LoggerAdapterNotDefinedError', () => {\n    expect(() => {\n      register(Container, {\n        logger: {\n          type: 'unknown-type',\n          name: 'UnknownTypeLogger',\n        },\n      });\n    }).to.throw(LoggerAdapterNotDefinedError);\n  });\n\n  it('should register logger with custom adapter', () => {\n    registerAdapter('custom', (config: any) => ({}));\n\n    register(Container, {\n      logger: {\n        name: 'firstLogger',\n        type: 'custom',\n      },\n    });\n    assert(Container.take('firstLogger'));\n  });\n\n  it('when custom adapter is broken should throw CouldNotRegisterLoggerInContainerError', () => {\n    registerAdapter('custom', null);\n\n    expect(() => {\n      register(Container, {\n        logger: {\n          name: 'firstLogger',\n          type: 'custom',\n        },\n      });\n    }).to.throw(CouldNotRegisterLoggerInContainerError);\n  });\n\n  it('when did not provided logger info then should throw ConfigNotDefinedError', () => {\n    expect(() => {\n      register(Container, {} as any);\n    }).to.throw(ConfigNotDefinedError);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-logger/src/adapters/__tests__/bunyan.ts",
    "content": "import { assert } from 'chai';\nimport * as sinon from 'sinon';\nimport * as bunyan from 'bunyan';\n\nimport { ILogger } from '../../types';\nimport bunyanAdapter from '../bunyan';\n\ndescribe('logger-adapter: bunyan', () => {\n  let logger: ILogger;\n\n  const spies: any = {\n    info: sinon.spy(),\n    debug: sinon.spy(),\n    warn: sinon.spy(),\n    error: sinon.spy(),\n  };\n\n  const createLoggerStub = sinon.stub(bunyan, 'createLogger');\n  createLoggerStub.returns(spies);\n\n  after(() => {\n    createLoggerStub.restore();\n  });\n  afterEach(() => {\n    Object.keys(spies).forEach((spy: string) => {\n      spies[spy].reset();\n    });\n  });\n\n  it('should create logger instance', () => {\n    logger = bunyanAdapter({\n      name: 'test',\n    });\n\n    assert('log' in logger);\n  });\n\n  it('should execute info method', () => {\n    logger.log('test');\n    assert(spies.info.called);\n  });\n\n  it('should execute debug method', () => {\n    logger.debug('test');\n    assert(spies.debug.called);\n  });\n\n  it('should execute warn method', () => {\n    logger.warn('test');\n    assert(spies.warn.called);\n  });\n\n  it('should execute error method', () => {\n    logger.error('test');\n    assert(spies.error.called);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-logger/src/adapters/bunyan.ts",
    "content": "import * as bunyan from 'bunyan';\nimport { ILogger, ILoggerConfig } from '../types';\n\nexport default (config: ILoggerConfig): ILogger => {\n  const logger: bunyan = bunyan.createLogger(config);\n  return {\n    log: (message: string) => {\n      logger.info(message);\n    },\n    debug: (message: string) => {\n      logger.debug(message);\n    },\n    warn: (message: string) => {\n      logger.warn(message);\n    },\n    error: (message: string) => {\n      logger.error(message);\n    },\n  };\n};\n"
  },
  {
    "path": "packages/hadron-logger/src/adapters/index.ts",
    "content": "import bunyan from '../adapters/bunyan';\nimport { ILogger, ILoggerFactory } from '../types';\n\nconst adapters: { [name: string]: ILoggerFactory } = {\n  bunyan,\n};\n\nexport default adapters;\n"
  },
  {
    "path": "packages/hadron-logger/src/errors/ConfigNotDefinedError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class ConfigNotDefinedError extends HadronErrorHandler {\n  constructor(error: Error = new Error()) {\n    super(`Config for hadron-logger package has not been found`);\n    this.error = error;\n    this.stack = error.stack;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-logger/src/errors/CouldNotRegisterLoggerInContainerError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class CouldNotRegisterLoggerInContainerError extends HadronErrorHandler {\n  constructor(name: string, error: Error = new Error()) {\n    super(`Could not create and register logger '${name}' in container.`);\n    this.error = error;\n    this.stack = error.stack;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-logger/src/errors/LoggerAdapterNotDefinedError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class LoggerAdapterNotDefinedError extends HadronErrorHandler {\n  constructor(name: string, error: Error = new Error()) {\n    super(`Logger adapter for ${name} has not been not found.`);\n    this.error = error;\n    this.stack = error.stack;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-logger/src/errors/LoggerNameIsRequiredError.ts",
    "content": "import HadronErrorHandler from '@brainhubeu/hadron-error-handler';\n\nexport default class LoggerNameIsRequiredError extends HadronErrorHandler {\n  constructor(error: Error = new Error()) {\n    super(`logger name is required to register in hadron`);\n    this.error = error;\n    this.stack = error.stack;\n  }\n}\n"
  },
  {
    "path": "packages/hadron-logger/src/logger.ts",
    "content": "import { IContainer } from '@brainhubeu/hadron-core';\n\nimport LoggerNameIsRequiredError from './errors/LoggerNameIsRequiredError';\nimport LoggerAdapterNotDefinedError from './errors/LoggerAdapterNotDefinedError';\nimport ConfigNotDefinedError from './errors/ConfigNotDefinedError';\nimport CouldNotRegisterLoggerInContainerError from './errors/CouldNotRegisterLoggerInContainerError';\n\nimport defaultAdapters from './adapters';\nimport {\n  ILogger,\n  ILoggerConfig,\n  ILoggerFactory,\n  IHadronLoggerConfig,\n} from './types';\n\nconst adapters: { [key: string]: ILoggerFactory } = { ...defaultAdapters };\n\nexport const registerAdapter = (\n  name: string,\n  adapter: ILoggerFactory,\n): void => {\n  adapters[name] = adapter;\n};\n\nconst register = (container: IContainer, config: IHadronLoggerConfig) => {\n  let { logger: loggers } = config;\n\n  if (!loggers) {\n    throw new ConfigNotDefinedError();\n  }\n\n  loggers = loggers instanceof Array ? loggers : [loggers];\n\n  loggers.forEach((logger: ILoggerConfig) => {\n    const { type = 'bunyan', ...loggerConfig } = logger;\n\n    if (!(type in adapters)) {\n      throw new LoggerAdapterNotDefinedError(type);\n    }\n\n    if (!logger.name) {\n      throw new LoggerNameIsRequiredError();\n    }\n\n    try {\n      const loggerInstance: ILogger = adapters[type](loggerConfig);\n      container.register(logger.name, loggerInstance);\n    } catch (error) {\n      throw new CouldNotRegisterLoggerInContainerError(logger.name);\n    }\n  });\n};\n\nexport { register };\nexport default register;\n"
  },
  {
    "path": "packages/hadron-logger/src/types.ts",
    "content": "export interface IHadronLoggerConfig {\n  logger: ILoggerConfig[] | ILoggerConfig;\n}\n\nexport interface ILoggerConfig {\n  type?: string;\n  name: string;\n}\n\nexport interface ILogger {\n  log?: (message: string) => void;\n  warn?: (message: string) => void;\n  debug?: (message: string) => void;\n  error?: (message: string) => void;\n}\n\nexport type ILoggerFactory = (config: ILoggerConfig) => ILogger;\n"
  },
  {
    "path": "packages/hadron-logger/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-oauth/.eslintrc",
    "content": "{\n  extends: 'brainhub'\n}\n"
  },
  {
    "path": "packages/hadron-oauth/.gitignore",
    "content": "*.swp\n"
  },
  {
    "path": "packages/hadron-oauth/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-oauth/README.md",
    "content": "## Installation\n\n`npm install --save @brainhubeu/hadron-oauth`\n\n## Overview\n\n`hadron-oauth` is a Hadron utility package to simplify working with OAuth providers, such as Google and Facebook. It provides several utility functions that you can use to make writing OAuth2 authentication quicker and more streamlined.\n\n## Tutorial\n\n### Understanding OAuth flow\n\nThe plan for our authentication flow is as follows:\n\n* The client makes a `GET` request to `/auth/{provider}` to begin the process of authentication.\n* The server redirects the client to a provider consent site.\n* The client receives an auth code.\n* The client makes a `POST` request to `/auth/{provider}/token` to exchange the auth code for an access token.\n\nWe can then use the access token to make further request to the provider's API in order to fetch data about the user (such as their name or email).\n\n### Configuration\n\nWe will need to provide certain information to `hadron-oauth` before we can proceed with the auth process. This information exists in Hadron's config file.\n\n```js\n// oauth.js\nmodule.exports = {\n  google: {\n    clientID: 'keyboard-cat',\n    clientSecret: 'shhh',\n    scope: ['https://www.googleapis.com/auth/userinfo.profile'],\n    redirectUri: 'http://localhost:8081/',\n  },\n};\n```\n\nThe `clientID` and `clientSecret` fields need to be the same as these given to you by your provider (such as the Google API Console). The `redirectUri` must be exactly the same as the one given to your provider.\n\n`scope` is an array of strings defining the scopes your app requires from the user. See the [Google scopes](https://developers.google.com/identity/protocols/googlescopes) and [Facebook scopes](https://developers.facebook.com/docs/facebook-login/permissions/) for details. These can be used later to retrieve relevant data from your provider's APIs about the user.\n\nIn this case, we'll also pretend that there is a front-end dev server at `http://localhost:8081`, however we can just as well redirect the calls back to our own server.\n\nIt's recommended that you exclude this file from your version control or supply the specific config fields through environment variables as this file contains sensitive information.\n\n### Registration\n\nNow that our config is created, we need to create our Hadron app entry point.\n\n```js\n// index.js\nconst hadron = require('@brainhubeu/hadron-core').default;\nconst hadronExpress = require('@brainhubeu/hadron-express');\nconst hadronOauth = require('@brainhubeu/hadron-oauth');\n\nconst express = require('express');\nconst oauthConfig = require('./oauth.js');\n\nconst app = express();\n\nconst config = {\n  oauth: oauthConfig,\n  routes: {\n    root: {\n      path: '/',\n      methods: ['GET'],\n      callback: () => 'Hello!',\n    },\n  },\n};\n\nhadron(app, [hadronExpress, hadronOauth], config).then(() => {\n  app.listen(8080, () => {\n    console.log('Hadron/Express listening on 8080.');\n  });\n});\n```\n\nWe now have access to the OAuth methods through the container.\n\n### Auth code route\n\nLet's create a separate file to store the logic for our route endpoints. We'll first create a route to redirect to the consent screen.\n\n```js\n// routes.js\nconst routes = {\n  googleAuthRequest: {\n    path: '/auth/google',\n    methods: ['GET'],\n    callback: (req, { oauth }) => ({\n      redirect: oauth.google.redirect(),\n    }),\n  },\n};\n\nmodule.exports = routes;\n```\n\n```js\n// index.js\nconst oauthRoutes = require('./routes');\n// ...\nconst config = {\n  routes: {\n    root: {\n      // ...\n    },\n    ...oauthRoutes,\n  },\n};\n```\n\nNow, whenever a client calls the `/auth/google` endpoint, he or she will be redirected to the Google auth consent page.\n\n### Handling the auth code\n\nNow, we'll delve into the client side here for a minute, because we need to send the auth code that the client receives back to the server.\n\nIn the `oauth.js` config file we defined a redirect to our front-end dev server. We now need to send the authorization code from that server back to our app.\n\nWe can do it like this:\n\n```js\n// client side javascript\nconst url = new URL(window.location);\nconst params = new URLSearchParams(url.search);\nconst code = params.get('code');\n\nif (!code) return;\n\nfetch('http://localhost:8080/auth/google/token', {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify({ code }),\n}).then((res) => {\n  // ...\n});\n```\n\n### Exchanging the code for an access token.\n\nWe'll define another route to exchange the auth code for an access token.\n\n```js\n// routes.js\nconst routes = {\n  googleAuthRequest: {\n    // ...\n  },\n  googleTokenRequest: {\n    path: '/auth/google/token',\n    methods: ['POST'],\n    callback: (req, { oauth }) => {\n      oauth.google.token(req.body.code).then((res) => {\n        console.log(res.access_token);\n        // do things with the token...\n      });\n    },\n  },\n};\n\nmodule.exports = routes;\n```\n\nNow that we have the access token we can implement other features, such as our own authentication. We can also call the Google API in the name of the user to pull any relevant information we need.\n\n## Reference\n\n### Config\n\n#### `google.`\n\n* `clientID: string` - your app id as provided by the [Google API Console](https://console.cloud.google.com/apis/credentials).\n* `clientSecret: string` - your app secret from the Google API Console\n* `scope: string[]` - an array of strings listing the [scope URLs](https://developers.google.com/identity/protocols/googlescopes) you need for your app.\n* `redirectUri: string` - redirect URI for your app, must be exactly the same as the one you chose in Google API Console.\n* `authUrl: ?string` - an optional parameter to provide a different auth URL to Google (for instance if the current one was to stop working). Defaults to `https://accounts.google.com/o/oauth2/v2/auth`.\n* `tokenUrl: ?string` - an optional parameter to provide a different token exchange Google API endpoint. Defaults to `https://www.googleapis.com/oauth2/v4/token`.\n* `responseType: ?string` - if Google was to support a different kind of OAuth authentication flow, we could specify the response type here. Currently, it only supports `code` and so it defaults to that.\n* `grantType: ?string` - similarly to the point above, if Google was to support a different kind of OAuth authentication flow, we could specify the grant type here. Defaults to `authorization_code`.\n\n#### `facebook.`\n\n* `clientID: string` - your app id as provided by the [App Dashboard](https://developers.facebook.com/apps/).\n* `clientSecret: string` - your app secret from the App Dashboard.\n* `scope: string[]` - an array of strings listing [Facebook API scopes](https://developers.facebook.com/docs/facebook-login/permissions/).\n* `redirectUri: string` - the redirect URI for your app, must be the same as in the App Dashboard.\n* `authUrl: ?string` - see above, defaults to `https://www.facebook.com/v3.0/dialog/oauth`.\n* `tokenUrl: ?string` - see above, defaults to `https://graph.facebook.com/v3.0/oauth/access_token`\n* `responseType` - see above, defaults to `code`.\n\n#### `github.`\n\n* `clientID: string` - your app id as provided in the [Github Developer Settings](https://github.com/settings/developers).\n* `clientSecert: string` - your app secret from the Developer Settings.\n* `scope: string[]` - an array of strings listing [Github API scopes](https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/).\n* `redirectUri: string` - the redirect URI for your app, must be the same as in the Developer Settings.\n* `authUrl: ?string` - see above, defaults to `https://github.com/login/oauth/authorize`.\n* `tokenUrl: ?string` - see above, defaults to `https://github.com/login/oauth/access_token`\n* `allowSignup: ?boolean` - determines whether the user will be able to sign up to Github while authorizing the app, defaults to `true`.\n\n### Methods\n\n#### `oauth.google.`\n\n* `redirect() => string` - parses the config options and returns a redirect URL to the user consent screen.\n* `token(code: string) => Promise` - exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the response from Google.\n\n#### `oauth.facebook.`\n\n* `redirect(state: ?string) => string` - parses the config and returns a redirect URL to the user consent screen. You can provide a state string to secure your app against CSRF ([see here for details](https://developers.facebook.com/docs/facebook-login/security/#stateparam)).\n* `token(code: string) => Promise` - exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the repsonse from Facebook.\n\n#### `oauth.github.`\n\n* `redirect(state: ?string) => string` - parses the config and returns a redirect URL to the user consent screen. You can provide a state string to secure your app against CSRF.\n* `token(code: string, state: ?string) => Promise` - exchanges the auth code in the first argument for an access token. Returns a promise which resolves to the repsonse from Facebook.\n"
  },
  {
    "path": "packages/hadron-oauth/index.ts",
    "content": "import { IOAuthConfig, IContainer } from './src/types';\n\nimport facebookRedirect from './src/facebook/redirect';\nimport googleRedirect from './src/google/redirect';\nimport githubRedirect from './src/github/redirect';\nimport facebookToken from './src/facebook/token';\nimport googleToken from './src/google/token';\nimport githubToken from './src/github/token';\n\nexport default {\n  facebook: {\n    redirect: facebookRedirect,\n    token: facebookToken,\n  },\n  google: {\n    redirect: googleRedirect,\n    token: googleToken,\n  },\n  github: {\n    redirect: githubRedirect,\n    token: githubToken,\n  },\n};\n\nconst oauthProvider = (oauthConfig: IOAuthConfig) => ({\n  facebook: {\n    redirect: (state?: string) => facebookRedirect(oauthConfig, state),\n    token: (code: string) => facebookToken(code, oauthConfig),\n  },\n  google: {\n    redirect: () => googleRedirect(oauthConfig),\n    token: (code: string) => googleToken(code, oauthConfig),\n  },\n  github: {\n    redirect: (state?: string) => githubRedirect(oauthConfig),\n    token: (code: string, state?: string) =>\n      githubToken(code, oauthConfig, state),\n  },\n});\n\nexport const register = (container: IContainer, config: any) => {\n  const oauthConfig = config.oauth as IOAuthConfig;\n\n  container.register('oauth', oauthProvider(oauthConfig));\n};\n\nexport { IOAuthConfig, IContainer } from './src/types';\n"
  },
  {
    "path": "packages/hadron-oauth/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-oauth\",\n  \"version\": \"1.0.2\",\n  \"description\": \"Hadron module for authorisation from OAuth2 providers.\",\n  \"main\": \"dist/index.js\",\n  \"license\": \"MIT\",\n  \"author\": \"Brainhub\",\n  \"keywords\": [\n    \"hadron\",\n    \"hadron-oauth\"\n  ],\n  \"scripts\": {\n    \"prepare\": \"tsc\",\n    \"test\": \"mocha -r ts-node/register src/__tests__/*\"\n  },\n  \"devDependencies\": {\n    \"@types/nock\": \"9.1.3\",\n    \"chai\": \"4.1.2\",\n    \"eslint-config-brainhub\": \"1.8.1\",\n    \"mocha\": \"5.2.0\",\n    \"nock\": \"9.3.3\",\n    \"ts-node\": \"6.1.1\"\n  },\n  \"dependencies\": {\n    \"@types/node-fetch\": \"2.1.1\",\n    \"node-fetch\": \"2.1.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-oauth/src/__tests__/facebook.ts",
    "content": "import { expect } from 'chai';\nimport * as nock from 'nock';\nimport * as url from 'url';\n\nimport generateRedirectUrl from '../facebook/redirect';\nimport requestToken from '../facebook/token';\n\nconst config = {\n  facebook: {\n    clientID: 'keyboard-cat',\n    clientSecret: 'shhh',\n    redirectUri: 'http://localhost:8080',\n    scope: ['profile'],\n  },\n};\n\n// @TODO: Errors and bad inputs.\ndescribe('facebook', function() {\n  it('generates a valid redirect url', function() {\n    const uri = generateRedirectUrl(config);\n    expect(url.parse(uri)).to.be.ok;\n  });\n\n  it('exchanges auth code for url', function(done) {\n    nock('https://graph.facebook.com')\n      .get('/v3.0/oauth/access_token')\n      .query((body: any) => {\n        if (\n          body.code &&\n          body.client_id &&\n          body.client_secret &&\n          body.redirect_uri\n        ) {\n          return true;\n        }\n      })\n      .reply(200, { access_token: 'bearhaslanded' });\n\n    requestToken('code', config).then((json) => {\n      expect(json.access_token).to.be.equal('bearhaslanded');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-oauth/src/__tests__/formatQueryString.ts",
    "content": "import { expect } from 'chai';\n\nimport formatQueryString from '../util/formatQueryString';\n\ndescribe('utils', function() {\n  it('formatQueryString should format an object into a correct url query string', function() {\n    const obj = { a: 5, b: 'potato' };\n\n    const query = formatQueryString(obj);\n\n    expect(query).to.be.equal('a=5&b=potato&');\n  });\n});\n"
  },
  {
    "path": "packages/hadron-oauth/src/__tests__/github.ts",
    "content": "import { expect } from 'chai';\nimport * as nock from 'nock';\nimport * as url from 'url';\n\nimport generateRedirectUrl from '../github/redirect';\nimport requestToken from '../github/token';\n\nconst config = {\n  github: {\n    clientID: 'keyboard-cat',\n    clientSecret: 'shhh',\n    redirectUri: 'http://localhost:8080',\n    scope: ['user'],\n  },\n};\n\n// @TODO: Errors and bad inputs.\ndescribe('github', function() {\n  it('generates a valid redirect url', function() {\n    const uri = generateRedirectUrl(config);\n    expect(url.parse(uri)).to.be.ok;\n  });\n\n  it('exchanges auth code for url', function(done) {\n    nock('https://github.com')\n      .post('/login/oauth/access_token', (body: any) => {\n        if (\n          body.code &&\n          body.client_id &&\n          body.client_secret &&\n          body.redirect_uri\n        ) {\n          return true;\n        }\n      })\n      .reply(200, { access_token: 'bearhaslanded' });\n\n    requestToken('code', config).then((json) => {\n      expect(json.access_token).to.be.equal('bearhaslanded');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-oauth/src/__tests__/google.ts",
    "content": "import { expect } from 'chai';\nimport * as nock from 'nock';\nimport * as url from 'url';\n\nimport generateRedirectUrl from '../google/redirect';\nimport requestToken from '../google/token';\n\nconst config = {\n  google: {\n    clientID: 'keyboard-cat',\n    clientSecret: 'shhh',\n    redirectUri: 'http://localhost:8080',\n    scope: ['https://www.googleapis.com/auth/userinfo.profile'],\n  },\n};\n\n// @TODO: Errors and bad inputs.\ndescribe('google', function() {\n  it('generates a valid redirect url', function() {\n    const uri = generateRedirectUrl(config);\n    expect(url.parse(uri)).to.be.ok;\n  });\n\n  it('exchanges auth code for url', function(done) {\n    nock('https://www.googleapis.com')\n      .post('/oauth2/v4/token', (body: any) => {\n        if (\n          body.code &&\n          body.client_id &&\n          body.client_secret &&\n          body.grant_type\n        ) {\n          return true;\n        }\n      })\n      .reply(200, { access_token: 'bearhaslanded' });\n\n    requestToken('code', config).then((json) => {\n      expect(json.access_token).to.be.equal('bearhaslanded');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-oauth/src/facebook/redirect.ts",
    "content": "import { IContainer, IOAuthConfig } from '../types';\nimport { FACEBOOK_AUTH_URL } from '../util/constants';\n\nimport formatQueryString from '../util/formatQueryString';\n\nexport default (config: IOAuthConfig, state?: string): string => {\n  const host = config.facebook.authUrl || FACEBOOK_AUTH_URL;\n\n  const query = {\n    client_id: config.facebook.clientID,\n    redirect_uri: config.facebook.redirectUri,\n    scope: config.facebook.scope.join(','),\n    response_type: config.facebook.responseType || 'code',\n    state: state || '',\n  };\n\n  const queryString = formatQueryString(query);\n\n  return `${host}?${queryString}`;\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/facebook/token.ts",
    "content": "import fetch from 'node-fetch';\n\nimport { IOAuthConfig } from '../types';\nimport formatQueryString from '../util/formatQueryString';\n\nimport { FACEBOOK_TOKEN_URL } from '../util/constants';\n\nexport default (code: string, config: IOAuthConfig): Promise<any> => {\n  const host = config.facebook.tokenUrl || FACEBOOK_TOKEN_URL;\n\n  const query = {\n    code,\n    client_id: config.facebook.clientID,\n    client_secret: config.facebook.clientSecret,\n    redirect_uri: config.facebook.redirectUri,\n  };\n\n  const queryString = formatQueryString(query);\n\n  return fetch(`${host}?${queryString}`).then((res) => res.json());\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/github/redirect.ts",
    "content": "import { IContainer, IOAuthConfig } from '../types';\nimport { GITHUB_AUTH_URL } from '../util/constants';\n\nimport formatQueryString from '../util/formatQueryString';\n\nexport default (config: IOAuthConfig, state?: string): string => {\n  const host = config.github.authUrl || GITHUB_AUTH_URL;\n\n  const query = {\n    client_id: config.github.clientID,\n    redirect_uri: config.github.redirectUri,\n    scope: config.github.scope.join(','),\n    state: state || '',\n  };\n\n  const queryString = formatQueryString(query);\n\n  return `${host}?${queryString}`;\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/github/token.ts",
    "content": "import fetch from 'node-fetch';\n\nimport { IOAuthConfig } from '../types';\n\nimport { GITHUB_TOKEN_URL } from '../util/constants';\n\nexport default (\n  code: string,\n  config: IOAuthConfig,\n  state?: string,\n): Promise<any> => {\n  const host = config.github.tokenUrl || GITHUB_TOKEN_URL;\n\n  const query = {\n    code,\n    state,\n    client_id: config.github.clientID,\n    client_secret: config.github.clientSecret,\n    redirect_uri: config.github.redirectUri,\n  };\n\n  return fetch(host, {\n    method: 'POST',\n    headers: {\n      'content-type': 'application/json',\n      Accept: 'application/json',\n    },\n    body: JSON.stringify(query),\n  }).then((res) => res.json());\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/google/redirect.ts",
    "content": "import { IContainer, IOAuthConfig } from '../types';\nimport { GOOGLE_AUTH_URL } from '../util/constants';\n\nimport formatQueryString from '../util/formatQueryString';\n\nexport default (config: IOAuthConfig): string => {\n  const host = config.google.authUrl || GOOGLE_AUTH_URL;\n\n  const query = {\n    client_id: config.google.clientID,\n    redirect_uri: config.google.redirectUri,\n    scope: config.google.scope.join(' '),\n    response_type: config.google.responseType || 'code',\n  };\n\n  const queryString = formatQueryString(query);\n\n  return `${host}?${queryString}`;\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/google/token.ts",
    "content": "import fetch from 'node-fetch';\n\nimport { IOAuthConfig } from '../types';\nimport formatQueryString from '../util/formatQueryString';\n\nimport { GOOGLE_TOKEN_URL } from '../util/constants';\n\nexport default (code: string, config: IOAuthConfig): Promise<any> => {\n  const host = config.google.tokenUrl || GOOGLE_TOKEN_URL;\n\n  const query = {\n    code,\n    client_id: config.google.clientID,\n    client_secret: config.google.clientSecret,\n    redirect_uri: config.google.redirectUri,\n    grant_type: config.google.grantType || 'authorization_code',\n  };\n\n  return fetch(host, {\n    method: 'POST',\n    headers: {\n      'content-type': 'application/x-www-form-urlencoded',\n    },\n    body: formatQueryString(query),\n  }).then((res) => res.json());\n};\n"
  },
  {
    "path": "packages/hadron-oauth/src/types.ts",
    "content": "export interface IContainer {\n  register: (key: string, value: any, lifecycle?: string) => any;\n  take: (key: string) => any;\n  keys: () => string[];\n}\n\nexport interface IOAuthConfig {\n  google?: {\n    clientID: string;\n    clientSecret: string;\n    scope: string[];\n    redirectUri: string;\n    authUrl?: string;\n    tokenUrl?: string;\n    responseType?: string;\n    grantType?: string;\n  };\n  facebook?: {\n    clientID: string;\n    clientSecret: string;\n    redirectUri: string;\n    scope: string[];\n    authUrl?: string;\n    tokenUrl?: string;\n    responseType?: string;\n  };\n  github?: {\n    clientID: string;\n    clientSecret: string;\n    redirectUri: string;\n    scope: string[];\n    authUrl?: string;\n    tokenUrl?: string;\n    allowSignup?: boolean;\n  };\n}\n\nexport interface IQueryObject {\n  [index: string]: any;\n}\n"
  },
  {
    "path": "packages/hadron-oauth/src/util/constants.ts",
    "content": "export const GOOGLE_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';\nexport const GOOGLE_TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';\n\nexport const FACEBOOK_AUTH_URL = 'https://www.facebook.com/v3.0/dialog/oauth';\nexport const FACEBOOK_TOKEN_URL =\n  'https://graph.facebook.com/v3.0/oauth/access_token';\n\nexport const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize';\nexport const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';\n"
  },
  {
    "path": "packages/hadron-oauth/src/util/formatQueryString.ts",
    "content": "import { IQueryObject } from '../types';\n\nexport default (query: IQueryObject): string => {\n  return Object.keys(query).reduce((acc, i) => {\n    return `${acc}${i}=${query[i]}&`;\n  }, '');\n};\n"
  },
  {
    "path": "packages/hadron-oauth/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-serialization/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-serialization/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-serialization --save\n```\n\n[More info about installation](http://hadron-docs.dev.brainhub.pl/core/#installation)\n\n## Overview\n\nSerializer allows You to quickly and easy shape and parse data way You want it. You just need to create schema (in json file, or as simple object) and You are ready to go!s\n\n## Initializing as Hadron package\n\nPass package as an argument for hadron bootstrapping function:\n\n```javascript\n// ... importing and initializing other components\n\nhadron(expressApp, [require('@brainhubeu/hadron-serialization')], config);\n```\n\nThat way, You should be able to get it from [Container](http://hadron-docs.dev.brainhub.pl/core/#dependency-injection) like that:\n\n```javascript\nconst serializer = container.take('serializer');\nserializer.addSchema({\n  name: 'User',\n  properties: [ ... ],\n});\n\n// ...\n\nconst data = { ... };\nserializer.serialize(data, 'User');\n// or\nconst data = new User();\nserializer.serialize(data);\n```\n\n## Initializing without Hadron\n\nJust import `serializerProvider` function from package and pass there Your [schemas](#schema) and parsers.\n\n```javascript\nconst serializerProvider = require('@brainhubeu/hadron-serialization');\n\nconst serializer = serializerProvider({\n  schemas: mySchemas,\n  parsers: {\n    superParser: (value) => `Super ${value}`,\n  },\n  // ...\n});\n```\n\n## Configuration\n\nIf You are using hadron application, You just need to add to it's config schemas and set of parsers:\n\n```javascript\nconst config = {\n  // ...\n  serializer: {\n    schemas: [ ... ],\n    parser: [ ... ],\n  }\n};\n```\n\nIf You are using TypeScript, You can just implement exported interface `ISerializerConfig`\n\n```typescript\ninterface ISerializerConfig {\n  parsers?: object;\n  schemas?: ISerializationSchema[];\n}\n```\n\n## Usage\n\nSerializer contain three methods.\n\n```javascript\nserialize(data, groups, schemaName);\n```\n\n* `data` - object we want to serialize\n* `groups` - optional array of access [groups](#groups), on default `[]`\n* `schemaName` - name of schema, on default name of passed object\n\n```javascript\naddSchema(schemaObj);\n```\n\n* `schemaObj` - [schema](#schema) object we want to add\n\n```javascript\naddParser(parser, name);\n```\n\nAdds parser that can be used in schemas, where:\n\n* `parser` is a method\n* `name` is name under which parser will be available\n\n## Schema\n\nSchema is basic structure, that allows You to easily define your desired object. You can provider them as `json` file. F.e.\n\n```json\n{\n  \"name\": \"User\",\n  \"properties\": [\n    { \"name\": \"name\", \"type\": \"string\" },\n    { \"name\": \"address\", \"type\": \"string\", \"groups\": [\"admin\"] },\n    {\n      \"name\": \"money\",\n      \"type\": \"number\",\n      \"parsers\": [\"currency\"],\n      \"groups\": [\"admin\"]\n    },\n    {\n      \"name\": \"friends\",\n      \"type\": \"array\",\n      \"properties\": [\n        { \"name\": \"name\", \"type\": \"string\" },\n        { \"name\": \"profession\", \"type\": \"string\", \"groups\": [\"admin\"] },\n        { \"name\": \"salary\", \"type\": \"number\", \"parsers\": [\"currency\"] }\n      ]\n    }\n  ]\n}\n```\n\nEach schema should contain `name`, which will be its identifier, and `properties` which should be an array of fields of defined schema.\n\nAll properties that are not defined in schema, will be excluded from the serialized data result.\n\nIf You are using TypeScript, You can just implement exported interface `ISerializationSchema`:\n\n```typescript\ninterface ISerializationSchema {\n  name: string;\n  properties: IProperty[];\n}\n```\n\n## Property\n\nEach property should contain such fields:\n\n* `name` - (required) name of the field\n* `type` - (required) one of such types:\n  * `string`\n  * `number`\n  * `bool`\n  * `array`\n  * `object`\n* `groups` - array of strings, that will define accessibility to this field ([link](#groups)). If empty, such field if public and will be returned always.\n* `parsers` - array of parsers name, that should be run on this field, before it's returned\n* `properties` - array of properties, that are required in case of type `object` and `array`\n* `serializedName` - name of field after serialization\n\nIf You are using TypeScript, You can just implement exported interface `IProperty`:\n\n```typescript\ninterface IProperty {\n  name: string;\n  type: string;\n  serializedName?: string;\n  groups?: string[];\n  parsers?: string[];\n  properties?: IProperty[];\n}\n```\n\n## Groups\n\nWhile defining schema, You can add `groups` parameter to properties. That way, while serializing data, You can specify serialization group.\n\n```javascript\nconst schema = {\n  name: 'User',\n  properties: [\n    // ...\n    { name: 'firstname', type: 'string' },\n    { name: 'lastname', type: 'string', groups: ['friends'] }\n  ],\n}\nserializer.addSchema(schema);\n\n// ...\n\nconst data = {\n  firstname: 'John',\n  lastname: 'Doe',\n  id: 481,\n};\n\nconsole.log(serializer.serialize(data, [], 'User');\n// { 'firstname': 'John' }\n\nconsole.log(serializer.serialize(data, ['friends'], 'User');\n// { 'firstname': 'John', 'lastname': 'Doe' }\n```\n"
  },
  {
    "path": "packages/hadron-serialization/index.ts",
    "content": "import * as interfaces from './src/types';\nimport { CONTAINER_NAME } from './src/constants';\nimport schema from './src/schema-provider';\nimport serializerProvider from './src/serializer';\nimport { IContainer } from '@brainhubeu/hadron-core';\n\nexport default serializerProvider;\n\nexport * from './src/constants';\n\nexport const schemaProvider = schema;\n\nexport type ISerializer = interfaces.ISerializer;\nexport type ISerializerConfig = interfaces.ISerializerConfig;\nexport type ISerializationSchema = interfaces.ISerializationSchema;\nexport type IProperty = interfaces.IProperty;\n\nexport const register = (\n  container: IContainer,\n  config: interfaces.IHadronSerializerConfig,\n) => {\n  const serializerConfig: interfaces.ISerializerConfig = {\n    ...config.serializer,\n  };\n  const serializer = serializerProvider(serializerConfig);\n  container.register(CONTAINER_NAME, serializer);\n};\n"
  },
  {
    "path": "packages/hadron-serialization/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-serialization\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hadron serialization module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-serialization\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"@brainhubeu/hadron-json-provider\": \"^1.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-serialization/src/__tests__/mocks.ts",
    "content": "import { IProperty, ISerializationSchema, ISerializerConfig } from '../types';\n\nexport const fruitConfiguration = {\n  name: 'Fruit',\n  properties: [\n    { name: '_id', type: 'string', serializedName: 'ID' } as IProperty,\n    { name: 'name', type: 'string' } as IProperty,\n    {\n      name: 'price',\n      groups: ['common', 'seller'],\n      type: 'number',\n    } as IProperty,\n    {\n      groups: ['seller'],\n      name: 'funkyName',\n      parsers: ['funkyParser'],\n      type: 'string',\n    } as IProperty,\n    {\n      name: 'flavour',\n      properties: [\n        {\n          name: 'bitterness',\n          type: 'number',\n        } as IProperty,\n        {\n          name: 'sweetness',\n          type: 'number',\n        } as IProperty,\n      ],\n      type: 'object',\n    },\n  ],\n} as ISerializationSchema;\n\nexport const carConfiguration = {\n  name: 'Car',\n  properties: [\n    { name: 'name', groups: ['common', 'seller'], type: 'string' } as IProperty,\n    {\n      name: 'price',\n      groups: ['common', 'seller'],\n      type: 'number',\n    } as IProperty,\n    {\n      groups: ['seller'],\n      name: 'type',\n      type: 'string',\n    } as IProperty,\n  ],\n} as ISerializationSchema;\n\nexport const options = {\n  parsers: {\n    funkyParser: (data: any) => `funky ${data}`,\n  },\n} as ISerializerConfig;\n"
  },
  {
    "path": "packages/hadron-serialization/src/__tests__/schema-provider.ts",
    "content": "import { expect } from 'chai';\nimport * as sinon from 'sinon';\nimport { ISerializationSchema, ISerializerConfig } from '../types';\nimport * as jsonProvider from '@brainhubeu/hadron-json-provider';\nimport schemaProvider from '../schema-provider';\n\ndescribe('schemaProvider', () => {\n  it('should try to locate files in given location', () => {\n    const mockResponse: any = [\n      { name: 'Test', properties: [] },\n      { name: 'Second', properties: [] },\n    ];\n\n    const jsonProviderStub = sinon\n      .stub(jsonProvider, 'default')\n      .callsFake(() => Promise.resolve(mockResponse));\n\n    const result = schemaProvider(['./test/location']);\n    jsonProviderStub.restore();\n\n    return expect(result).to.eventually.be.eql(mockResponse);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-serialization/src/__tests__/serializer.ts",
    "content": "import { expect } from 'chai';\nimport * as sinon from 'sinon';\nimport serializerProvider, {\n  hasIntersection,\n  serialize,\n  serializeEntry,\n} from '../serializer';\nimport { carConfiguration, fruitConfiguration } from './mocks';\n\nimport { IProperty, ISerializer } from '../types';\n\ndescribe('serializer', () => {\n  describe('hasIntersection', () => {\n    it('should return true if at least one element is common for both arrays', () => {\n      expect(hasIntersection([1, 2, 3], [3, 4, 5])).to.eql(true);\n    });\n\n    it('should return false if no elements are common for both arrays', () => {\n      expect(hasIntersection([1, 2, 3], [4, 5, 6])).to.eql(false);\n    });\n\n    it('should return false if one of arrays are empty', () => {\n      expect(hasIntersection([1, 2, 3], [])).to.eql(false);\n    });\n  });\n\n  describe('serializeEntry()', () => {\n    it('should run parse method for defined type', () => {\n      const parsers = {\n        number: sinon.spy(Number),\n      };\n\n      const property = {\n        name: 'price',\n        type: 'number',\n      };\n\n      serializeEntry('123', ['common'], property, parsers);\n      expect(parsers.number.calledWith('123'));\n    });\n\n    it('should run parse method for defined type', () => {\n      const parsers = {\n        number: sinon.spy(Number),\n      };\n\n      const property = {\n        name: 'price',\n        type: 'number',\n      };\n\n      serializeEntry('123', ['common'], property, parsers);\n      expect(parsers.number.calledWith('123'));\n    });\n  });\n\n  describe('serialize()', () => {\n    it('should exclude properties not belonging to configuration', () => {\n      const data = {\n        absent: \"I shouldn't be here\",\n        name: 'Civic',\n        price: '12000',\n        type: 'hatchback',\n      };\n      expect(\n        serialize(data, ['seller'], carConfiguration.properties, {}),\n      ).to.not.contain.keys(['absent']);\n    });\n\n    it('should include properties belonging to group', () => {\n      const data = {\n        name: 'Civic',\n        price: '12000',\n        type: 'hatchback',\n      };\n      expect(\n        serialize(data, ['common'], carConfiguration.properties, {}),\n      ).to.contain.keys(['name', 'price']);\n    });\n\n    it('should run parsers before returning value', () => {\n      const data = {\n        name: 'Civic',\n        price: '12000',\n        type: 'hatchback',\n      };\n      const parsers = { number: sinon.spy(Number) };\n      serialize(data, ['common'], carConfiguration.properties, parsers);\n      expect(parsers.number.calledWith('12000')).to.be.eql(true);\n    });\n\n    it('should include nested parameters', () => {\n      const data = {\n        flavour: {\n          bitterness: '2',\n          sweetness: '12',\n        },\n        name: 'Pear',\n        price: '20',\n      };\n      const result = serialize(\n        data,\n        ['common'],\n        fruitConfiguration.properties,\n        {},\n      );\n      expect(result).to.have.property('flavour');\n    });\n\n    it('should parse nested parameters', () => {\n      const data = {\n        flavour: {\n          bitterness: '2',\n          sweetness: '12',\n        },\n        name: 'Pear',\n        price: '20',\n      };\n      const parsers = {\n        number: sinon.spy(Number),\n      };\n\n      serialize(data, ['common'], fruitConfiguration.properties, parsers);\n\n      expect(parsers.number.calledThrice).to.eql(true);\n    });\n\n    it('should set key as defined serializedName', () => {\n      const data = {\n        _id: '12',\n        flavour: {\n          bitterness: '2',\n          sweetness: '12',\n        },\n        name: 'Pear',\n        price: '20',\n      };\n      const result = serialize(\n        data,\n        ['common'],\n        fruitConfiguration.properties,\n        {},\n      );\n      expect(result).to.have.property('ID');\n    });\n\n    it('should serialize object with given properties', () => {\n      const serializerProperties = {\n        name: 'objectProperty',\n        properties: [\n          { name: 'String', type: 'string' },\n          { name: 'Number', type: 'number' },\n        ],\n        type: 'object',\n      } as IProperty;\n\n      const data = {\n        objectProperty: {\n          String: '123',\n          Number: 456,\n        },\n      };\n      expect(\n        serialize(data, ['common'], [serializerProperties], {}),\n      ).to.be.deep.equal({\n        objectProperty: {\n          Number: 456,\n          String: '123',\n        },\n      });\n    });\n\n    it('should exclude properties from other gorups from object serialization', () => {\n      const serializerProperties = {\n        name: 'objectProperty',\n        properties: [\n          { name: 'String', type: 'string' },\n          { name: 'Number', type: 'number', groups: ['uncommon'] },\n        ],\n        type: 'object',\n      } as IProperty;\n\n      const data = {\n        objectProperty: {\n          String: '123',\n          Number: 456,\n        },\n      };\n      expect(\n        serialize(data, ['common'], [serializerProperties], {}),\n      ).to.be.deep.equal({\n        objectProperty: {\n          String: '123',\n        },\n      });\n    });\n\n    it('should serialize array with given properties and groups', () => {\n      const serializerProperties = {\n        name: 'arrayProperties',\n        properties: [\n          { name: 'String', type: 'string', groups: ['common'] },\n          { name: 'Number', type: 'number', groups: ['uncommon'] },\n        ],\n        type: 'array',\n      } as IProperty;\n\n      const data = {\n        arrayProperties: [\n          { String: '123', Number: 456 },\n          { String: '222', Number: 123 },\n        ],\n      };\n      expect(\n        serialize(data, ['common'], [serializerProperties], {}),\n      ).to.be.deep.equal({\n        arrayProperties: [\n          {\n            String: '123',\n          },\n          {\n            String: '222',\n          },\n        ],\n      });\n    });\n\n    it('should parse array of serializable elements', () => {\n      const serializerProperties = {\n        name: 'arrayProperties',\n        properties: [\n          { name: 'CommonString', type: 'string' },\n          { name: 'String', type: 'string' },\n        ],\n        type: 'array',\n      } as IProperty;\n\n      const data = {\n        arrayProperties: [\n          {\n            CommonString: 'lorem ipsum',\n            String: 'dolor',\n            NoString: 'sit amet',\n            Number: 12,\n          },\n        ],\n      };\n      expect(\n        serialize(data, ['common'], [serializerProperties], {}),\n      ).to.be.deep.equal({\n        arrayProperties: [\n          {\n            CommonString: 'lorem ipsum',\n            String: 'dolor',\n          },\n        ],\n      });\n    });\n\n    it(\"should exclude parameters from array, that doesn't belong to group\", () => {\n      const serializerProperties = {\n        name: 'arrayProperties',\n        properties: [\n          { name: 'CommonString', type: 'string' },\n          { name: 'String', type: 'string', groups: ['common'] },\n          { name: 'Number', type: 'number', groups: ['uncommon'] },\n        ],\n        type: 'array',\n      } as IProperty;\n\n      const data = {\n        arrayProperties: [\n          {\n            CommonString: 'lorem ipsum',\n            String: 'dolor',\n            NoString: 'sit amet',\n            Number: 12,\n          },\n        ],\n      };\n      expect(\n        serialize(data, ['common'], [serializerProperties], {}),\n      ).to.be.deep.equal({\n        arrayProperties: [\n          {\n            CommonString: 'lorem ipsum',\n            String: 'dolor',\n          },\n        ],\n      });\n    });\n  });\n\n  describe('serializerProvider()', () => {\n    it('should add configuration dynamically', () => {\n      const serializer: ISerializer = serializerProvider({});\n      serializer.addSchema(carConfiguration);\n      const data = {\n        name: 'Civic',\n        price: '12000',\n        type: 'hatchback',\n      };\n      expect(\n        serializer.serialize(data, ['common'], 'Car'),\n      ).to.eventually.contain.keys(['name', 'price']);\n    });\n\n    it('should add parser dynamically', () => {\n      const serializer: ISerializer = serializerProvider({\n        schemas: [\n          {\n            name: 'Test',\n            properties: [\n              {\n                name: 'parsesParams',\n                parsers: ['testParser'],\n                type: 'Something',\n              },\n            ],\n          },\n        ],\n      });\n      const parserSpy = sinon.spy();\n      serializer.addParser(parserSpy, 'testParser');\n      const data = {\n        parsesParams: 'smth',\n      };\n      return serializer\n        .serialize(data, ['common'], 'Test')\n        .then(() => expect(parserSpy.called).to.eql(true));\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-serialization/src/constants.ts",
    "content": "export const DATA_TYPE = {\n  NUMBER: 'number',\n  BOOL: 'bool',\n  STRING: 'string',\n  OBJECT: 'object',\n  ARRAY: 'array',\n};\n\n// name in container\nexport const CONTAINER_NAME = 'serializer';\n"
  },
  {
    "path": "packages/hadron-serialization/src/declarations.d.ts",
    "content": "declare module '@hadron/json-provider';\n"
  },
  {
    "path": "packages/hadron-serialization/src/schema-provider.ts",
    "content": "import jsonProvider from '@brainhubeu/hadron-json-provider';\n\nexport default (paths: string[]) => {\n  if (paths.length >= 0) {\n    try {\n      return jsonProvider(paths, ['json'], true);\n    } catch (error) {\n      return Promise.reject(new Error(`Incorrect configuration: ${error}`));\n    }\n  }\n\n  return Promise.resolve([]);\n};\n"
  },
  {
    "path": "packages/hadron-serialization/src/serializer.ts",
    "content": "import {\n  IProperty,\n  ISerializationSchema,\n  ISerializer,\n  ISerializerConfig,\n} from './types';\n\nimport { DATA_TYPE } from './constants';\n\nconst defaultParsers = {\n  [DATA_TYPE.BOOL]: Boolean,\n  [DATA_TYPE.NUMBER]: Number,\n  [DATA_TYPE.STRING]: String,\n};\n\n/**\n * Searches for property\n *\n * @param key \"name\" of current property\n * @param properties list of available properties\n */\nexport const getPropertyForKey = (\n  key: string,\n  properties: IProperty[] = [],\n): IProperty => properties.find((property: IProperty) => property.name === key);\n\n/**\n * Searches for parser\n *\n * @param names array of names for parsers, one of them should be \"type\" of property,\n * other are additional parsers defined in property\n * @param availableParsers list of available parsers\n */\nexport const getParsers = (names: string[], availableParsers: object) => {\n  const namesSet = new Set(names);\n  return (Object as any)\n    .entries(availableParsers)\n    .filter(([key, parser]: [string, any]) => namesSet.has(key))\n    .map(([key, parser]: [string, any]) => parser);\n};\n\n/**\n * Searches for configration\n *\n * @param type \"name\" of current serialization\n * @param configurations list of available configurations\n */\nexport const getConfigurationForType = (\n  type: string,\n  configurations: ISerializationSchema[],\n) =>\n  configurations.find(\n    (configuration: ISerializationSchema) => configuration.name === type,\n  );\n\n/**\n * Checks if given arrays have at least one common memer\n *\n * @param firstArray\n * @param secondArray\n */\nexport const hasIntersection = (\n  firstArray: any[],\n  secondArray: any[],\n): boolean => {\n  const secondArraySet = new Set(secondArray);\n  return (\n    firstArray.filter((value: any) => secondArraySet.has(value)).length > 0\n  );\n};\n\n/**\n * Serializes object with given properties, excluding ones not existing in properties array\n *\n * @param data\n * @param groups serialization groups\n * @param properties list of available properties\n * @param parsers list of available parsers\n */\nexport const serialize = (\n  data: object,\n  groups: string[],\n  properties: IProperty[],\n  parsers: object,\n) =>\n  (Object as any)\n    .entries(data)\n    // exclude properties not present in schema or not containing proper group\n    .filter(([key, value]: [string, any]) => {\n      const property = getPropertyForKey(key, properties);\n      // if parameter has no groups, its public\n      return (\n        property &&\n        (!property.groups || hasIntersection(property.groups, groups))\n      );\n    })\n    .reduce((result: any, [key, value]: [string, any]) => {\n      const property = getPropertyForKey(key, properties);\n      const propertyKey = property.serializedName || key;\n      return Object.assign(\n        result,\n        // tslint:disable:no-use-before-declare\n        { [propertyKey]: serializeEntry(value, groups, property, parsers) },\n      );\n    }, {});\n\n/**\n *  Serializes one single entry\n *\n * @param value\n * @param groups current serialization group\n * @param property instance of property, which contains informations about serialization\n * @param availableParsers all available parsers\n */\nexport const serializeEntry = (\n  value: any,\n  groups: string[],\n  property: IProperty,\n  availableParsers: object,\n): any => {\n  const parsers = getParsers(\n    [...(property.parsers || []), property.type],\n    availableParsers,\n  );\n  let serializedValue = value;\n\n  if (property.properties && property.type === DATA_TYPE.OBJECT) {\n    serializedValue = serialize(\n      value,\n      groups,\n      property.properties,\n      availableParsers,\n    );\n  }\n\n  if (property.properties && property.type === DATA_TYPE.ARRAY) {\n    serializedValue = value\n      .map((childValue: any) =>\n        serialize(childValue, groups, property.properties, availableParsers),\n      )\n      .reduce(\n        (result: any[], currentValue: any) => [...result, currentValue],\n        [],\n      );\n  }\n\n  if (parsers) {\n    serializedValue = parsers.reduce(\n      (accumulator: any, parser: (data: any) => any) => parser(accumulator),\n      serializedValue,\n    );\n  }\n  return serializedValue;\n};\n\n/**\n * Function provider for serialization\n *\n * @param configuration array of serialize configurations\n * @param options options for serializer, like path to configuration files, or additional parsers\n */\nconst serializerProvider = (config: ISerializerConfig) => {\n  const parsers = {\n    ...defaultParsers,\n    ...(config.parsers || {}),\n  } as any;\n\n  const schemas = config.schemas || [];\n  return {\n    addParser: (parser: (data: any) => any, key: string) => {\n      parsers[key] = parser;\n      return parser;\n    },\n    addSchema: (schema: ISerializationSchema) => {\n      schemas.push(schema);\n      return schemas;\n    },\n    serialize: (data: any, groups: string[], configurationName?: string) => {\n      // if configurationName is not defined, we are trying to get name from instance of object\n      const name = configurationName || data.constructor.name;\n      const foundConfiguration = schemas.find(\n        (configuration: ISerializationSchema) => configuration.name === name,\n      );\n      if (!foundConfiguration) {\n        return Promise.reject(new Error('Configuration not found'));\n      }\n      return Promise.resolve(foundConfiguration).then(\n        (schema: ISerializationSchema) =>\n          data && serialize(data, groups, schema.properties, parsers),\n      );\n    },\n  } as ISerializer;\n};\n\nexport default serializerProvider;\n"
  },
  {
    "path": "packages/hadron-serialization/src/types.ts",
    "content": "export interface ISerializationSchema {\n  name: string;\n  properties: IProperty[];\n}\n\nexport interface IProperty {\n  name: string;\n  serializedName?: string;\n  groups?: string[];\n  type: string;\n  parsers?: string[];\n  properties?: IProperty[];\n}\n\nexport interface ISerializerConfig {\n  parsers?: object;\n  schemas?: ISerializationSchema[];\n}\n\nexport interface IHadronSerializerConfig {\n  serializer: ISerializerConfig;\n}\n\nexport interface ISerializer {\n  addParser: (parser: (data: any) => any, key: string) => object;\n  addSchema: (schema: ISerializationSchema) => ISerializationSchema[];\n  serialize: (\n    data: any,\n    groups: string[],\n    configurationName?: string,\n  ) => Promise<any>;\n}\n"
  },
  {
    "path": "packages/hadron-serialization/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-typeorm/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-typeorm --save\n```\n\n[More info about installation](/core/#installation)\n\n## Initializing\n\nPass package as an argument for hadron bootstrapping function:\n\n```javascript\nconst hadronTypeOrm = require('@brainhubeu/hadron-typeorm');\n// ... importing and initializing other components\n\nhadron(expressApp, [hadronTypeOrm], config).then(() => {\n  console.log('Hadron with typeORM initialized');\n});\n```\n\n## Connecting to database\n\nYou can set up a new connection using [connection object](http://typeorm.io/#/connection).\n\n```javascript\n{\n  connectionName: string,\n  type: string,\n  host: string,\n  port: number,\n  username: string,\n  password: string,\n  database: string\n  entitySchemas: entities,\n  synchronize: bool,\n}\n```\n\n* `connectionName` - string that identifies this connection\n* `type` - string that defines type of database, f.e. mysql, mariadb, postgres, sqlite, mongodb,\n* `host` - url to database,\n* `port` - port of database,\n* `username` - username of account to databse,\n* `password` - password to database,\n* `database` - name of database\n* `entities` - array of classes that defines models\n* `entitySchemas` - in case that You are describing models with schemas, put those in this parameter\n* `synchronize` - parameter that defines if database should be automatically synchronized with models\n\nAlso all other parameters available in typeOrm are available. Please take a look at [TypeORM documentation](https://github.com/typeorm/typeorm#creating-a-connection-to-the-database)\n\n## Including database connection in hadron\n\n_NOTE: Also events aren't included in this section so logging into the console is done using setTimeout._\n\nSince we have our connection, we need to include it inside our hadron constructor's config object.\n\n```javascript\nconst hadronTypeOrm = require('@brainhubeu/hadron-typeorm');\n\nconst config = {\n  connection: {\n    /* connection object */\n  },\n};\n\nhadron(expressApp, [hadronTypeOrm], config).then((container) => {\n  console.log('Initialized connection:', container.take('connection'));\n});\n```\n\n## Entities\n\nLet's assume we want to have a simple table **user**\n\n| Field     | Type    |\n| --------- | ------- |\n| 🔑 id     | int     |\n| firstName | varchar |\n| lastName  | varchar |\n\nWe have two options while defining our `entities`.\n\n### Class + Decorators\n\n```typescript\nimport { Entity, Column, PrimaryColumn } from 'typeorm';\n\n@Entity()\nexport class Photo {\n  @PrimaryGeneratedColumn()\n  @Column()\n  id: number;\n\n  @Column() firstName: string;\n\n  @Column() lastName: string;\n}\n```\n\nWhen using this method, while creating connection to database, those classes should be in `entities` parameter.\n\n### Schema Way\n\n```javascript\n// entity/User.js\n\nmodule.exports = {\n  name: 'User',\n  columns: {\n    id: {\n      primary: true,\n      type: 'int',\n      generated: true,\n    },\n    firstName: {\n      type: 'varchar',\n    },\n    lastName: {\n      type: 'varchar',\n    },\n  },\n};\n```\n\nWhen using this method, while creating connection to database, those schemas should be in `entitySchemas` parameter.\n\nFor more details about defining models, please take a look at [TypeORM documentation](http://typeorm.io/#/entities). Especially section about [available types](http://typeorm.io/#/entities/column-types) for each database distribution\n\n## Injecting entities into hadron\n\nTo include our entities in hadron, we simply need to include them in our config object.\nLet's modify the code that we were using to initialize hadron:\n\n```javascript\nconst hadronTypeOrm = require('@brainhubeu/hadron-typeorm');\nconst user = require('./entity/User');\n\nconst config = {\n  connection,\n  entities: [user],\n};\n\nhadron(expressApp, [hadronTypeOrm], config).then((container) => {\n  console.log(\n    'userRepository available:',\n    container.take('userRepository') !== null,\n  );\n  // User entity should be declared under userRepository key and\n  // will be available as a typeORM repository\n});\n```\n\nRepository key in Container depends from name of schema/class and is builded in such way:\n`<schema/class name in camelCase>Repository`\n\nExamples:\n\n```\nUser = userRepository\nSuperUser = superUserRepository\nloremIpsumDolor = loremIpsumDolorRepository\n```\n\n## Repositories\n\nGenerater repositories contain same methods as ones from TypeORM. Please check them out here:\n\n[http://typeorm.io/#/working-with-entity-manager](http://typeorm.io/#/working-with-entity-manager)\n\n## Troubleshooting\n\n### I can' connect to database:\n\n* make sure that connection config has valid data and there is existing database with specified name\n\n### There are no tables in my database\n\n* There are few possible reasons for that. Firstly check if parameter `synchronize` in configuration is set to true.\n\n* Then make sure that connection configuration contains `entities`/`entitySchemas` fields.\n\n* Remember, if You are using class definition of models, You need to put them in `entities` parameter, otherwise (schema method) in `entitySchemas`\n\n### There is an information that I am missing a driver\n\n* If you decided which database You want to use, You need to add a proper driver to your dependencies. For more details check TypeORM [README](https://github.com/typeorm/typeorm#installation) file\n"
  },
  {
    "path": "packages/hadron-typeorm/index.ts",
    "content": "import { connect } from './src/connectionHelper';\nimport * as constants from './src/constants';\nimport { IHadronTypeormConfig } from './src/types';\nimport { IContainer } from '@brainhubeu/hadron-core';\n\nexport const register = (\n  container: IContainer,\n  config: IHadronTypeormConfig,\n): Promise<void> => connect(container, config);\n\nexport { connect, constants, IHadronTypeormConfig };\n"
  },
  {
    "path": "packages/hadron-typeorm/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-typeorm\",\n  \"version\": \"1.0.3\",\n  \"description\": \"Hadron typeorm module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"typeorm\",\n    \"hadron-typeorm\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@brainhubeu/hadron-core\": \"^1.0.0\",\n    \"typeorm\": \"0.1.16\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/src/__tests__/connectionHelper.ts",
    "content": "import { assert } from 'chai';\nimport * as sinon from 'sinon';\nimport * as typeorm from 'typeorm';\nimport { Container } from '@brainhubeu/hadron-core';\n\nimport { connect } from '../connectionHelper';\nimport { CONNECTION } from '../constants';\n\nimport { Team } from './mocks/entity/Team';\nimport { User } from './mocks/entity/User';\nimport { UserStatus } from './mocks/entity/UserStatus';\nimport userSchema from './mocks/schema/User';\n\nconst connection: typeorm.ConnectionOptions = {\n  name: 'mysql-connection',\n  type: 'mysql',\n  host: 'localhost',\n  port: 3306,\n  username: 'root',\n  password: 'my-secret-pw',\n  database: 'test',\n  entities: [Team, User, UserStatus],\n};\n\ndescribe('TypeORM connection helper', () => {\n  const createConnectionStub = sinon.stub(typeorm, 'createConnection');\n  createConnectionStub.returns(\n    new Promise((resolve) => {\n      resolve(new typeorm.Connection(connection));\n    }),\n  );\n\n  const getRepositoryStub = sinon.stub(\n    typeorm.Connection.prototype,\n    'getRepository',\n  );\n  getRepositoryStub.returns(true);\n\n  beforeEach(() => {\n    Container.register('connection', null);\n    Container.register('teamRepository', null);\n    Container.register('userRepository', null);\n  });\n\n  after(() => {\n    createConnectionStub.restore();\n    getRepositoryStub.restore();\n  });\n\n  it('should return connection', () =>\n    connect(Container, { connection }).then((connection: any) => {\n      return assert(connection instanceof typeorm.Connection);\n    }));\n\n  it('should register connection to container', () => {\n    connect(Container, { connection }).then((connection: any) => {\n      assert(Container.take(CONNECTION) instanceof typeorm.Connection);\n    });\n  });\n\n  it('should register Team repository to container as teamRepository', () =>\n    connect(Container, { connection }).then((connection: any) =>\n      assert(Container.take('teamRepository')),\n    ));\n\n  it('should register UserStatus repository to container as userstatusRepository', () =>\n    connect(Container, { connection }).then((connection: any) =>\n      assert(Container.take('userstatusRepository')),\n    ));\n\n  it('should register User repository from javascript schema to container as userRepository', () =>\n    connect(Container, {\n      connection: {\n        ...connection,\n        entities: [],\n        entitySchemas: [userSchema],\n      },\n    }).then((connection: any) => assert(Container.take('userRepository'))));\n});\n"
  },
  {
    "path": "packages/hadron-typeorm/src/__tests__/mocks/entity/Team.ts",
    "content": "import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\nimport { User } from './User';\n\n@Entity()\nexport class Team {\n  @PrimaryGeneratedColumn() public id: number;\n\n  @Column({ type: 'text' })\n  public name: string;\n\n  @OneToMany((type) => User, (user) => user.team)\n  public users: User[];\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/src/__tests__/mocks/entity/User.ts",
    "content": "import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';\nimport { Team } from './Team';\nimport { UserStatus } from './UserStatus';\n\n@Entity()\nexport class User {\n  @PrimaryGeneratedColumn() public id: number;\n\n  @Column({ type: 'text' })\n  public name: string;\n\n  @ManyToOne((type) => Team, (team) => team.users)\n  public team: Team;\n\n  @ManyToOne((type) => UserStatus, (userStatus) => userStatus.users)\n  public userStatus: UserStatus;\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/src/__tests__/mocks/entity/UserStatus.ts",
    "content": "import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\nimport { User } from './User';\n\n@Entity()\nexport class UserStatus {\n  @PrimaryGeneratedColumn() public id: number;\n\n  @Column({ type: 'text' })\n  public name: string;\n\n  @OneToMany((type) => User, (user) => user.status)\n  public users: User[];\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/src/__tests__/mocks/schema/User.ts",
    "content": "export default {\n  name: 'User',\n  columns: {\n    id: {\n      primary: true,\n      type: 'int',\n      generated: true,\n    },\n    name: {\n      type: 'string',\n    },\n    team: {\n      type: 'string',\n    },\n  },\n};\n"
  },
  {
    "path": "packages/hadron-typeorm/src/connectionHelper.ts",
    "content": "import { createConnection, Connection, EntityOptions } from 'typeorm';\nimport { CONNECTION } from './constants';\nimport { IContainer } from '@brainhubeu/hadron-core';\nimport { IHadronTypeormConfig } from './types';\n\nconst repositoryName = (name: string) => `${name.toLowerCase()}Repository`;\n\nconst registerRepositories = (\n  container: IContainer,\n  connection: Connection,\n  entities: Array<string | EntityOptions>,\n) => {\n  entities.forEach((entity: string | EntityOptions) => {\n    const name: string = typeof entity === 'string' ? entity : entity.name;\n\n    container.register(repositoryName(name), connection.getRepository(name));\n  });\n};\n\nconst registerConnection = (\n  container: IContainer,\n  connection: Connection,\n): Connection => {\n  container.register(CONNECTION, connection);\n  return connection;\n};\n\nconst connect = (\n  container: IContainer,\n  config: IHadronTypeormConfig,\n): Promise<any> => {\n  const { connection } = config;\n\n  return createConnection(connection)\n    .then((connection) => registerConnection(container, connection))\n    .then((connection: Connection) => {\n      const entitiesToRegister = [\n        ...(config.connection.entities || []),\n        ...(config.connection.entitySchemas || []),\n      ];\n      registerRepositories(container, connection, entitiesToRegister);\n\n      return connection;\n    })\n    .catch((err) => {\n      console.error(err);\n    });\n};\n\nexport { connect, registerRepositories };\n"
  },
  {
    "path": "packages/hadron-typeorm/src/constants.ts",
    "content": "export const CONNECTION = 'connection';\n"
  },
  {
    "path": "packages/hadron-typeorm/src/types.ts",
    "content": "import { ConnectionOptions } from 'typeorm';\n\nexport interface IHadronTypeormConfig {\n  connection: ConnectionOptions | any;\n}\n"
  },
  {
    "path": "packages/hadron-typeorm/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-utils/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-utils/README.md",
    "content": "# Utility tools for Hadron\n"
  },
  {
    "path": "packages/hadron-utils/index.ts",
    "content": "import getArgs from './src/getArgs';\n\nexport { getArgs };\n"
  },
  {
    "path": "packages/hadron-utils/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-utils\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Set of utility functions for hadron\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"utils\",\n    \"brainhub\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-utils/src/__tests__/getArgs.ts",
    "content": "/* tslint:disable:max-classes-per-file */\nimport { expect } from 'chai';\nimport getArgs from '../getArgs';\n\ndescribe('getArgs return list of arguments', () => {\n  it(\"function declaration - should return ['bar', 'bar2']\", () => {\n    function foo(bar: any, bar2: any): any {\n      return null;\n    }\n    const args = getArgs(foo);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"function expression - should return ['bar', 'bar2']\", () => {\n    const foo = (bar: any, bar2: any) => {\n      const t = '';\n      return t;\n    };\n    const args = getArgs(foo);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"class declaration - should return ['bar', 'bar2']\", () => {\n    class Foo {\n      constructor(bar: any, bar2: any) {\n        return null;\n      }\n    }\n    const args = getArgs(Foo);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"class expression - should return ['bar', 'bar2']\", () => {\n    const foo = class {\n      constructor(bar: any, bar2: any) {\n        const t = '';\n        return t;\n      }\n    };\n    const args = getArgs(foo);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"object method is no constructable - should return ['bar', 'bar2']\", () => {\n    const foo = {\n      foo(bar: any, bar2: any): any {\n        return null;\n      },\n    }.foo;\n    const args = getArgs(foo);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"class method - should return ['bar', 'bar2']\", () => {\n    class Foo {\n      public bar(bar: any, bar2: any): any {\n        return null;\n      }\n    }\n    const bar = new Foo().bar;\n    const args = getArgs(bar);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n  it(\"static class method - should return ['bar', 'bar2']\", () => {\n    class Foo {\n      public static bar(bar: any, bar2: any): any {\n        return null;\n      }\n    }\n    const bar = Foo.bar;\n    const args = getArgs(bar);\n    expect(['bar', 'bar2']).to.deep.equal(args);\n  });\n});\n"
  },
  {
    "path": "packages/hadron-utils/src/getArgs.ts",
    "content": "const getArgs = (f: (args: any) => any): string[] => {\n  const STRIP_COMMENTS = /((\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/))/gm;\n  const ARGUMENT_NAMES = /([^\\s,]+)/g;\n  const funcContent = f.toString().replace(STRIP_COMMENTS, '');\n  return (\n    funcContent\n      .slice(funcContent.indexOf('(') + 1, funcContent.indexOf(')'))\n      .match(ARGUMENT_NAMES) || []\n  );\n};\n\nexport default getArgs;\n"
  },
  {
    "path": "packages/hadron-utils/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "packages/hadron-validation/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Brainhub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/hadron-validation/README.md",
    "content": "## Installation\n\n```bash\nnpm install @brainhubeu/hadron-validation --save\n```\n\n[More info about installation](/core/#installation)\n\n## Creating schema files\n\nTo use validation layer, first you need to provide some schemas. We use JSON Schema format, for example:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"number\"\n    },\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"age\": {\n      \"type\": \"number\"\n    }\n  },\n  \"required\": [\"name\", \"age\"],\n  \"additionalProperties\": false\n}\n```\n\nFull documentation about JSON Schema: [Ajv documentation](https://epoberezkin.github.io/ajv/)\n\n## Preparing schema files for usage with Hadron\n\nWhen your schemas are ready you need to build object from them, where **key name** is a name of the schema, for example:\n\n```js\n// schemas.js\n\nconst insertTeam = require('./team/insertTeam.json');\nconst updateTeam = require('./team/updateTeam.json');\nconst insertUser = require('./user/insertUser.json');\nconst updateUser = require('./user/updateUser.json');\n\nconst schemas = {\n  insertTeam,\n  updateTeam,\n  insertUser,\n  updateUser,\n};\n\nmodule.exports = schemas;\n```\n\n## Validate function\n\nAfter you create schemas object you can create validate function from **Hadron validator factory**\n\n```js\n// validate.js\n\nconst validatorFactory = require('@brainhubeu/hadron-validation');\nconst schemas = require('./schemas');\n\nmodule.exports = validatorFactory(schemas);\n```\n\n## Using validate function\n\nAfter you created validate function with **hadron validator factory** you can use it to validate object by schemas you provide.\n\n```js\nconst validObject = {\n  name: 'Max',\n  age: 22,\n};\n\nvalidate('schemaName', objectToValidate)\n  .then((validObject) => {\n    console.log('I am a valid object', validObject);\n  })\n  .catch((error) => {\n    console.log('Object is invalid', error);\n  });\n```\n\nValidate function passes valid object, otherwise it throws an error.\n"
  },
  {
    "path": "packages/hadron-validation/index.ts",
    "content": "import validatorFactory from './src/validator-factory';\n\nexport default validatorFactory;\n"
  },
  {
    "path": "packages/hadron-validation/package.json",
    "content": "{\n  \"name\": \"@brainhubeu/hadron-validation\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Hadron validation layer module\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\",\n    \"./LICENSE\"\n  ],\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"tsc\"\n  },\n  \"keywords\": [\n    \"hadron\",\n    \"brainhub\",\n    \"hadron-validation\"\n  ],\n  \"author\": \"Brainhub\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"ajv\": \"6.4.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/Team.ts",
    "content": "import { User } from './User';\n\nexport class Team {\n  public id: number;\n  public name: string;\n  public users: User[];\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/User.ts",
    "content": "import { Team } from './Team';\n\nexport class User {\n  public id: number;\n  public name: string;\n  public team: Team;\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/declarations.d.ts",
    "content": "declare module '*.json' {\n  const value: any;\n  // @ts-ignore\n  export default value;\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas/email.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"html\": {\n      \"type\": \"string\"\n    },\n    \"text\": {\n      \"type\": \"string\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas/person.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"firstname\": {\n      \"type\": \"string\"\n    },\n    \"lastname\": {\n      \"type\": \"string\"\n    },\n    \"age\": {\n      \"type\": \"number\"\n    }\n  },\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas/team.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"number\"\n    },\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"users\": {\n        \"$ref\": \"users\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas/user.json",
    "content": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"id\": {\n      \"type\": \"number\"\n    },\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"team\": {\n        \"$ref\": \"team\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas/users.json",
    "content": "{\n  \"type\": \"array\",\n  \"description\": \"users in team\",\n  \"items\": {\n    \"$ref\": \"user\"\n  }\n}\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-schemas.ts",
    "content": "import email = require('./test-schemas/email.json');\nimport person = require('./test-schemas/person.json');\nimport team = require('./test-schemas/team.json');\nimport user = require('./test-schemas/user.json');\nimport users = require('./test-schemas/users.json');\n\nconst schemas = {\n  email,\n  person,\n  team,\n  user,\n  users,\n};\n\nexport default schemas;\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/__mocks__/test-validate.ts",
    "content": "import schemas from './test-schemas';\nimport validatorFactory from '../../validator-factory';\n\nexport default validatorFactory(schemas);\n"
  },
  {
    "path": "packages/hadron-validation/src/__tests__/validate.ts",
    "content": "import { expect } from 'chai';\nimport { Team } from './__mocks__/Team';\nimport { User } from './__mocks__/User';\nimport validate from './__mocks__/test-validate';\n\ndescribe('Validate', () => {\n  it('should pass valid email', () => {\n    const validEmail = {\n      html: 'abc',\n      text: 'abc',\n    };\n\n    return validate('email', validEmail).then((data) => {\n      expect(data).to.be.deep.equal(validEmail);\n    });\n  });\n\n  it('should return error if email is invalid', () => {\n    const invalidEmail = {\n      html: 'abc',\n      text: 1,\n    };\n\n    return validate('email', invalidEmail).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n    });\n  });\n\n  it('should pass valid user', () => {\n    const team = new Team();\n    team.id = 1;\n    team.name = 'Team One';\n\n    const user = new User();\n    user.id = 1;\n    user.name = 'Max';\n    user.team = team;\n\n    return validate('user', user).then((data) => {\n      expect(data).to.be.deep.equal(user);\n    });\n  });\n\n  it('should return error if user team is null', () => {\n    const user = new User();\n    user.id = 1;\n    user.name = 'Max';\n    user.team = null;\n\n    return validate('user', user).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n    });\n  });\n\n  it('should check if users in team are User objects', () => {\n    const dummyArr = [null, new User()];\n    const team = new Team();\n    team.id = 1;\n    team.name = 'Team';\n    team.users = dummyArr;\n\n    return validate('team', team).catch((error) => {\n      expect(error).to.be.an.instanceof(Error);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/hadron-validation/src/validator-factory.ts",
    "content": "import * as JsonSchemaValidator from 'ajv';\n\nconst factory = (schemas: any) => {\n  const validator = new JsonSchemaValidator({ allErrors: true });\n\n  Object.keys(schemas).forEach((key) => {\n    const schema = Object.assign(\n      {\n        $async: true,\n        $schema: 'http://json-schema.org/draft-07/schema#',\n        title: key,\n      },\n      schemas[key],\n    );\n\n    validator.addSchema(schema, key);\n  });\n\n  return (name: string, dataToValidate: any) => {\n    return new Promise((resolve, reject) => {\n      const validation = validator.validate(name, dataToValidate);\n      if (validation instanceof Promise) {\n        validation\n          .then(resolve)\n          .catch((error) =>\n            reject(\n              Error(`Error: ${error.message} ${JSON.stringify(error.errors)}`),\n            ),\n          );\n      } else {\n        return validation === true\n          ? resolve(dataToValidate)\n          : reject(Error('Error: Validation failed.'));\n      }\n    });\n  };\n};\n\nexport default factory;\n"
  },
  {
    "path": "packages/hadron-validation/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "pm2.config.js",
    "content": "module.exports = {\n  apps: [\n    {\n      name: process.env.NAME,\n      script: 'index.js',\n      instances: Number(process.env.CONCURRENT || 1),\n      exec_mode: 'cluster',\n      log_type: 'json',\n    },\n  ],\n};\n"
  },
  {
    "path": "scripts/clean",
    "content": "lerna clean --yes\nfor d in $PWD/packages/* ; do\n  echo \"Clearing dist in $d\";\n  cd $d && rm -rf dist\ndone\n"
  },
  {
    "path": "scripts/copy-tsconfig",
    "content": "for d in ./packages/* ; do\n  echo \"$d\";\n  cp tsconfig.json ./$d/\ndone\n"
  },
  {
    "path": "test.sh",
    "content": "#!/bin/bash\nport=\"${PORT:-8080}\"\n\ntrap 'kill $!' EXIT\n\nPORT=\"$port\" npm run start:test &\ntries=0\nwhile ! echo exit 1 | nc localhost \"$port\";\ndo\n  if ((tries >= 10))\n  then\n    echo 'Cannot connect to test server!'\n    exit 1;\n  fi\n  ((tries++))\n  sleep 5;\ndone\nnpm run test:cucumber\n"
  },
  {
    "path": "tools/testSetup.ts",
    "content": "import * as chai from 'chai';\nimport * as chaiAsPromised from 'chai-as-promised';\nimport * as dirtyChai from 'dirty-chai';\nimport * as sinonChai from 'sinon-chai';\n\nchai.use(chaiAsPromised);\nchai.use(sinonChai);\nchai.use(dirtyChai);\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"noImplicitAny\": true,\n    \"noEmitOnError\": true,\n    \"moduleResolution\": \"node\",\n    \"sourceMap\": true,\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"*\": [\"./*\"]\n    },\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"inlineSources\": true,\n    \"lib\": [\"es2017\", \"dom\"]\n  },\n  \"include\": [\"src/**/*.*\", \"index.ts\", \"LICENSE\"],\n  \"exclude\": [\"node_modules\", \"**/__tests__/**\", \"**/*/*.d.ts\"]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"extends\": [\n    \"tslint:recommended\",\n    \"tslint-config-airbnb\",\n    \"tslint-eslint-rules\",\n    \"tslint-config-prettier\"\n  ],\n  \"rules\": {\n    \"no-console\": {\n      \"severity\": \"warning\",\n      \"options\": [\"debug\", \"info\", \"log\", \"time\", \"timeEnd\", \"trace\"]\n    },\n    \"no-conditional-assignment\": true,\n    \"no-debugger\": true,\n    \"switch-default\": true,\n    \"forin\": true,\n    \"no-arg\": true,\n    \"no-empty\": true,\n    \"no-invalid-this\": false,\n    \"label-position\": true,\n    \"no-multi-spaces\": true,\n    \"no-unused-expression\": true,\n    \"no-return-assign\": false,\n    \"no-string-throw\": true,\n    \"radix\": true,\n    \"no-shadowed-variable\": false,\n    \"no-unused-variable\": [true, { \"ignore-pattern\": \"^I\" }],\n    \"no-use-before-declare\": true,\n    \"variable-name\": true,\n    \"one-variable-per-declaration\": true,\n    \"object-literal-sort-keys\": false,\n    \"ordered-imports\": false,\n    \"comment-format\": [true, \"check-space\"],\n    \"no-duplicate-imports\": true,\n    \"no-var-keyword\": true,\n    \"object-literal-shorthand\": true,\n    \"prefer-const\": true,\n    \"prefer-template\": true,\n    \"import-name\": false,\n    \"prefer-array-literal\": false,\n    \"no-parameter-reassignment\": false,\n    \"align\": false\n  },\n  \"linterOptions\": {\n    \"exclude\": [\"**/*.js\"]\n  }\n}\n"
  }
]